设计模式之原型模式
原型设计模式(Prototype)是创建型设计模式。
原型设计模式指通过已有的对象生成新的对象,我们无需知道原有的对象具体的创建细节,通常用于创建复杂的对象。
被克隆对象必须具备以下条件:
- 实现Cloneable接口,因为在JavaJVM中,如果要执行clone()方法时,发现该类没有实现Cloneable接口就会报CloneNotSupportedException异常;
- 重写Object的clone()方法;
原型模式优点
- 通过clone创建对象和通过new对象相比性能要后很多,因为Object的clone是native类型的,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显;
- 简化创建对象流程;
所以在重复创建相似类型的对象可以考虑使用原型模式,比如在循环体内创建对象时。
注意事项
- 原型模式创建对象不会执行被克伦对象的构造函数;
- 深克隆和浅克隆
- 深克隆:如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝;
- 浅克隆:Object类的clone方法只会拷贝对象中的基本的数据类型(8种基本数据类型byte,char,short,int,long,float,double,boolean),对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝;
原型模式-浅克隆
import java.util.Date; public class User implements Cloneable{ private String name; private Date birthday; public User(String name, Date birthday) { this.name = name; this.birthday = birthday; } @Override public String toString() { return "User [name=" + name + ", birthday=" + birthday + "]"; } @Override public Object clone() throws CloneNotSupportedException { return super.clone(); }
......(省略get/set)
}
测试类
public class Client { public static void main(String[] args) { try { Date birthday = new Date(1472692739L); User user01 = new User("parry", birthday); System.out.println("User01" + user01.toString()); User user02 = (User) user01.clone(); System.out.println("User02" + user02.toString()); birthday.setTime(1451577600l); System.out.println("修改birthdayUser01:" + user01.toString()); System.out.println("修改birthdayUser02:" + user02.toString()); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } }
测试结果:
说明:从测试结果看,修改了birthday之后,user01和user02都发生了发生了变化;其实浅克隆对非基本数据类型是不会拷贝的,还是引用,用下面的图表示
原型模式-深克隆(在克隆的时候对属性也进行克隆)
public class User implements Cloneable{ private String name; private Date birthday; public User(String name, Date birthday) { this.name = name; this.birthday = birthday; } @Override public String toString() { return "User [name=" + name + ", birthday=" + birthday + "]"; } @Override public Object clone() throws CloneNotSupportedException { User user = (User) super.clone(); user.birthday = (Date) this.birthday.clone();//属性克隆实现深克隆 return user; } ......(省略get/set) }
测试结果:
说明:从测试结果看,修改了birthday之后,只有user01的birthday发生了变化;其实深克隆对非基本数据类型会重新克隆一份,用面的图表示: