原型模式:通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。就是java中的克隆技术,以某个对象为原型,复制出新的对象。显然,新的对象具备原型对象的特点。
优势:效率高(直接克隆,避免了重新执行构造步骤)。
克隆类似于new,但是不同于new。new创建新的对象属性采用的是默认值。克隆出的对象的属性值完全和原型对象相同。并且克隆出的新对象改变不会影响原型对象。然后,再修改克隆对象的值。
原型模式实现:
Cloneable接口和clone方法。
Prototype模式中实现起来最困难的地方就是内存复制操作,所幸在Java中提供了clone()方法替我们做了绝大部分事情。
浅复制和深复制:
例:浅复制
定义一个Sheep类:
1 package com.ztq.prototype; 2 3 import java.util.Date; 4 5 public class Sheep implements Cloneable{ 6 private String sname; 7 private Date birthday; 8 9 @Override 10 protected Object clone() throws CloneNotSupportedException { 11 Object obj = super.clone(); //直接调用Object对象的clone()方法 12 return obj; 13 } 14 15 public String getSname() { 16 return sname; 17 } 18 19 public void setSname(String sname) { 20 this.sname = sname; 21 } 22 23 public Date getBirthday() { 24 return birthday; 25 } 26 27 public void setBirthday(Date birthday) { 28 this.birthday = birthday; 29 } 30 31 public Sheep(String sname, Date birthday) { 32 super(); 33 this.sname = sname; 34 this.birthday = birthday; 35 } 36 37 public Sheep(){} 38 }
测试类:
1 package com.ztq.prototype; 2 3 import java.util.Date; 4 5 /*** 6 * 测试原型模式(浅复制) 7 * @author ZTQ 8 * 9 */ 10 public class Client2 { 11 public static void main(String[] args) throws CloneNotSupportedException { 12 Date date = new Date(123123123123L); 13 Sheep s1 = new Sheep("aa", date); 14 Sheep s2 = (Sheep)s1.clone(); 15 16 System.out.println(s1.getBirthday()); 17 18 date.setTime(234234234L); 19 20 System.out.println(s1.getBirthday()); 21 System.out.println(s2.getBirthday()); 22 } 23 }
打印结果:
Mon Nov 26 08:52:03 GMT+08:00 1973 Sun Jan 04 01:03:54 GMT+08:00 1970 Sun Jan 04 01:03:54 GMT+08:00 1970
可见,s2克隆的s1,更改时间后,s2的birthday属性也跟着改变了。
深复制:
将重新的clone方法中添加代码:
1 @Override 2 protected Object clone() throws CloneNotSupportedException { 3 Object obj = super.clone(); //直接调用Object对象的clone()方法 4 5 //添加如下代码实现深复制 6 Sheep s = (Sheep)obj; 7 s.birthday = (Date)this.birthday.clone(); 8 9 return obj; 10 }
打印结果:
Mon Nov 26 08:52:03 GMT+08:00 1973 Sun Jan 04 01:03:54 GMT+08:00 1970 Mon Nov 26 08:52:03 GMT+08:00 1973
时间改变后,s2的birthday属性并没有随之改变。
序列化和反序列化实现深复制:
1 public class Client2 { 2 public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException { 3 Date date = new Date(123123123123L); 4 Sheep s1 = new Sheep("aa", date); 5 System.out.println(s1); 6 System.out.println(s1.getSname()); 7 System.out.println(s1.getBirthday()); 8 // Sheep s2 = (Sheep)s1.clone(); 9 // 使用序列化和反序列化实现深复制 10 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 11 ObjectOutputStream oos = new ObjectOutputStream(bos); 12 oos.writeObject(s1); 13 byte[] bytes = bos.toByteArray(); 14 15 ByteArrayInputStream bis = new ByteArrayInputStream(bytes); 16 ObjectInputStream ois = new ObjectInputStream(bis); 17 Sheep s2 = (Sheep)ois.readObject(); //克隆好的对象 18 19 date.setTime(234234234L); 20 21 System.out.println(s1.getBirthday()); 22 System.out.println(s2.getBirthday()); 23 }
打印结果:
com.ztq.prototype.Sheep@133c5982 aa Mon Nov 26 08:52:03 GMT+08:00 1973 Sun Jan 04 01:03:54 GMT+08:00 1970 Mon Nov 26 08:52:03 GMT+08:00 1973
开发中的应用场景:
——原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。
spring中bean的创建实际就是两种:单例模式和原型模式。(当然,原型模式需要和工厂模式搭配起来)
总结:
创建者模式:都是用来帮助我们创建对象的。
——单例模式:
保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。
——工厂模式:
简单工厂模式:用来生产同一等级结构中的任意产品。(对于增加新的产品,需要修改已有代码)
工厂方法模式:用来生产同一等级结构中的固定产品。(支持增加任意产品)
抽象工厂模式:用来生产不同产品族的全部产品。(对于增加新的产品,无能为力;支持增加产品族)
——建造者模式:
分离了对象子组件的单独构造(由Builder来负责)和装配(由Director负责),从而可以构造出复杂的对象。
——原型模式:
通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。