设计模式-原型模式

原型模式
原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。个人理解:就是根据一个对象实例通过一定的方式去快速创建对象新实例。调用者不用调用任何构造函数也不用关心具体创建细节。
原型模式属于创建性模式。

原型模式主要使用场景:创建新对象时需要很多的赋值操作(比如几十次调用 set get 方法),或者构造方法执行、实例的初始化 都需要很多不必要的过程, 需要消耗大量的资源。这个时候我们可以通过原型模式 不调用构造方法,不写N多行的 get set代码。通过调用指定方法快速获取实例。比如常用的 clone() BeanUtils.copy() JsonObject.parse 这些方法都可以让我们快速创建自己的实例。都是原型模式的一种。

浅克隆
java提供的clonable接口为浅克隆。一个类 克隆实例中的 字符串 integer int 类型的 属性 和原对象中的属性值没有任何关系(新实例中属性取值改变不会影响原实例中的取值) 但是对于引用类型这种 ,新实例中的值和旧实例中的值存放的是同一个对象的引用。 修改这个属性中字段值的时候 原实例中该属性字段的值也会变。 这就是浅克隆的概念。即对于嵌套的引用类型没有进行克隆 而只是将引用改地址复制到了克隆对象中。测试代码如下:

public class TestClone implements Cloneable{
    private String name;//字符串类型
    private Integer age; //integer 类型
    private int sex; //基本类型
    private TestClone obj; //引用各类型

    public TestClone getObj() {
        return obj;
    }
    public void setObj(TestClone obj) {
        this.obj = obj;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public int getSex() {
        return sex;
    }
    public void setSex(int sex) {
        this.sex = sex;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    @Override
    public String toString() {
        String res=name+"="+age +"="+sex+"; obj:"+obj.getName()+"="+obj.getAge()+"="+obj.getSex();
        return  res;
    }
    public static void main(String[] args) throws CloneNotSupportedException {
        TestClone t =  new TestClone();
        t.setName("zhangsan");
        t.setSex(1);
        t.setAge(300);
        t.setObj(t);
        TestClone t2= (TestClone)t.clone();

        System.out.println("t.getAge()==t2.getAge()"+(t.getAge()==t2.getAge()));//true
        System.out.println("t.getName()==t2.getName()"+(t.getName()==t2.getName()));//true
        System.out.println("t.getSex()==t2.getSex()"+(t.getSex()==t2.getSex()));//true
        t.setName("zhangsan2");
        t2.setSex(2);
        t2.setAge(10);
        System.out.println(t2.getObj().getName());
        System.out.println(t.toString() + t2.toString());
        System.out.println(t.getObj() == t2.getObj());
        System.out.println(t.getAge()== t2.getAge());
    }

深克隆
实现深克隆的方式
1.重写clone方法时对引用类型的属性再进行克隆。如果引用类型的属性中 又包含 引用各类型属性就需要层层克隆。所以该种方法再这种情况下回比较麻烦。
2.使用对象流将对象序列化 然后再反序列化回来就可以了
深克隆代码如下:

public class DeepClone implements  Serializable,Cloneable {
private String name;//字符串类型
private Integer age; //integer 类型
private int sex; //基本类型
private DeepClone obj; //引用类型
public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public Integer getAge() {
    return age;
}

public void setAge(Integer age) {
    this.age = age;
}

public int getSex() {
    return sex;
}

public void setSex(int sex) {
    this.sex = sex;
}

public DeepClone getObj() {
    return obj;
}

public void setObj(DeepClone obj) {
    this.obj = obj;
}
@Override
public Object clone() throws CloneNotSupportedException {
    try{
        ByteArrayOutputStream  bos = new ByteArrayOutputStream( );
        ObjectOutputStream oos = new ObjectOutputStream(bos );
        oos.writeObject(this);
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis   );
        Object o = ois.readObject();
        return (DeepClone)o;
    }catch(Exception e){
        e.printStackTrace();
    }
    return null;
}
public static void main(String[] args) throws Exception {
    DeepClone t =  new DeepClone();
    t.setName("zhangsan");
    t.setSex(1);
    t.setAge(300);
    t.setObj(t);
    DeepClone t2= (DeepClone)t.clone();
    System.out.println(t2.getObj()==t.getObj());
}

}

输出结果:
设计模式-原型模式
ArrayList 实现了Cloneable接口 并在clone 方法中实现了深克隆,如下 浅克隆之后又对实例的元素进行了深度克隆。
设计模式-原型模式