首页 > 技术文章 > 3,原型模式

Zender 2017-07-18 17:38 原文

一、什么是原型模式

原型模式(Prototype)模式是一种对象创建型模式,它采取复制原型对象的方法来创建对象的实例。使用 原型模式(Prototype)模式创建的实例,具有与原型一样的数据。

二、原型模式的特点

1,由原型对象自身创建目标对象。也就是说,对象创建这一动作发自原型对象本身。

2,目标对象是原型对象的一个克隆。也就是说,通过Prototype模式创建的对象,不仅仅与原型对象具有相同的结构,还与原型对象具有相同的值。

3,根据对象克隆深度层次的不同,有浅度克隆与深度克隆。

三、例子

创建一个原型类:

一个原型类,只需要实现Cloneable接口,覆写clone方法,此处clone方法可以改成任意的名称,因为Cloneable接口是个空接口。

public class Persion implements Cloneable{
    // 姓名
    private String name;
    // 年龄
    private int age;
    // 性别
    private String sex;
    //地址
    private List<String> addr;
    
    public List<String> getAddr() {
        return addr;
    }
    public void setAddr(List<String> addr) {
        this.addr = addr;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    //浅复制
    public Persion clone() {
        try {
            return (Persion) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}

创建一个测试类:

public class TestClass {
    public static void main(String[] args) {
        Persion p1 = new Persion();
        List<String> list = new ArrayList<String>();
        list.add("测试地址");
        p1.setAge(11);
        p1.setName("张三");
        p1.setSex("男");
        p1.setAddr(list);
        
        System.out.println("P1:age:" + p1.getAge() + " name:" + p1.getName() + " sex:" + p1.getSex() + " addr:" + p1.getAddr().toString());
        //复制一个Persion对象
        Persion p2 = p1.clone();
        System.out.println("P2:age:" + p2.getAge() + " name:" + p2.getName() + " sex:" + p2.getSex() + " addr:" + p1.getAddr().toString());
        
        //修改后的P2
        p2.setAge(15);
        p2.setName("未完");
        p2.setSex("女");
        //向p1再次添加了一个地址,这会影响到p2的addr,可以看出浅复制对于引用类型复制的是引用类型的地址
        list.add("测试地址2");
        p1.setAddr(list);
        //修改p2并不会影响到p1,
        System.out.println("修改后的P1:age:" + p1.getAge() + " name:" + p1.getName() + " sex:" + p1.getSex() + " addr:" + p1.getAddr().toString());
        System.out.println("修改后的P2:age:" + p2.getAge() + " name:" + p2.getName() + " sex:" + p2.getSex() + " addr:" + p2.getAddr().toString());
    }
}

浅复制和深复制:

        浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。

        深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。

可以看出浅复制对于引用类型只是复制了内存地址,并不是把引用类型再复制一份。我们可以深复制可以吧把引用类型也复制一份。

修改persion的clone方法如下:

//深复制
public Persion clone() {
    try {
        Persion p2 =  (Persion) super.clone();
        List<String> newAddrs = new ArrayList<String>();
        for (String string : addr) {
            newAddrs.add(string);
        }
        p2.setAddr(newAddrs);
        return p2;
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
        return null;
    }
}

同样的测试代码再次运行:这次并没有影响到p2

三、原型模式应用场景

1,在创建对象的时候,我们不只是希望被创建的对象继承其基类的基本结构,还希望继承原型对象的数据。

2,希望对目标对象的修改不影响既有的原型对象(深度克隆的时候可以完全互不影响)。

3,隐藏克隆操作的细节。很多时候,对对象本身的克隆需要涉及到类本身的数据细节。

推荐阅读