原型模式:通過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產生一個對象需要非常繁瑣的數據准備或訪問權限,則可以使用原型模式。