设计模式-原型模式
原型模式
原型模式(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 方法中实现了深克隆,如下 浅克隆之后又对实例的元素进行了深度克隆。