設計模式(五)原型模式
1、簡介
原型模式使用原型例項指定建立物件的種類,並且通過拷貝原型物件建立新的物件。提供了應該通過已存在物件進行新物件建立的介面clone。原型模式實際上就是從一個物件再建立另外一個可定製的物件,並且不需要知道建立的細節。在初始化的資訊不發生變化的情況下,克隆是最好的辦法,既隱藏了物件建立的細節,又大大提高了效能。因為如果不用clone,每次new都需要執行一次建構函式,如果建構函式執行時間很長,那麼多次的執行初始化操作太低效了。
原型模式實現clone介面的時候必須使用深拷貝。
原型模式的重點在從自身賦值自己建立新的類物件,隱藏建立的細節。
2、類圖
3、原型模式角色
(1)抽象原型(Prototype)角色:規定了具體原型物件必須實現的介面(如果要提供深拷貝,則必須具有實現clone的規定);
(2)具體原型(Concrete Prototype):從抽象原型派生而來,是客戶程式使用的物件,即被複制的物件,需要實現抽象原型角色所要求的介面;
(3)客戶端(Client):使用原型物件的客戶端程式。
4、原型模式使用場景
原型模式的主要思想是基於現有的物件克隆一個新的物件出來,一般是由物件的內部提供克隆的方法,通過clone方法返回一個物件的副本。
如:
- 當一個系統應該獨立於它的產品建立、構成和表示時,要使用原型模式;
- 當要例項化的類是在執行時刻指定時,如通過動態裝載;
- 為了避免建立一個與產品類層次平行的工廠類層次時;
- 當一個類的例項只能有幾個不同狀態組合中的一種時。建立相應數目的原型並克隆原型可能比每次用合適的狀態手工例項化原型類更方便一些。
5、優缺點
優點:
- 原型模式對客戶隱藏了具體的產品類;
- 執行時刻增加和刪除產品:原型模式允許只通過客戶註冊原型例項就可以將一個新的具體產品類併入系統;
- 改變值以指定新物件:高度動態的系統允許通過物件複合定義新的行為。如通過為一個物件變數指定值並且不定義新的類。通過例項化已有類並且將例項註冊為客戶物件的原型,就可以有效定義新類別的物件。客戶可以將職責代理給原型,從而表現出新的行為;
- 改變結構以指定新物件:許多應用由部件和子部件來建立物件;
- 減少子類的構造,Prototype模式克隆一個原型而不是請求一個工廠方法去產生一個新的物件;
- 用類動態配置應用一些執行時刻環境允許動態將類裝載到應用中;
- 使用原型模式建立物件比直接new一個物件在效能上要好的多,因為Object類的clone方法是一個本地方法,直接操作記憶體中的二進位制流,特別是複製大物件時,效能的差別非常明顯;
- 使用原型模式的另一個好處是簡化物件的建立,使得建立物件很簡單。
缺點:
原型模式的主要缺陷是每一個抽象原型Prototype的子類都必須實現clone操作,實現clone函式可能會很困難。當所考慮的類已經存在時就難以新增clone操作,當內部包括一些不支援拷貝或有迴圈引用的物件時,實現克隆可能也會很困難的。
6、淺拷貝與深拷貝
(1)淺拷貝
被拷貝物件的所有變數都含有與原物件相同的值,而且對其他物件的引用仍然是指向原來的物件。即淺拷貝只負責當前物件例項,對引用的物件不做拷貝。
(2)深拷貝
被拷貝物件的所有的變數都含有與原來物件相同的值,除了引用其他物件的變數。引用其他物件的變數將指向一個被拷貝的新物件,而不再是原有被引用物件。即深拷貝把要拷貝的物件所引用的物件也都拷貝了一次。
深拷貝要深入到多少層,是一個不確定的問題。在決定以深拷貝的方式拷貝一個物件的時候,必須決定對間接拷貝的物件是採取淺拷貝還是深拷貝還是繼續採用深拷貝。因此,在採取深拷貝時,需要決定多深才算深。此外,在深拷貝的過程中,很可能會出現迴圈引用的問題。
7、程式碼例項
(1)淺拷貝
1 /** 2 * @author it-小林 3 * @desc 4 * @date 2021年07月14日 20:08 5 * 步驟 6 * 1、實現一個介面 Cloneable 7 * 2、重寫一個方法 clone() 8 */ 9 public class Video implements Cloneable { 10 11 private String name; 12 13 private Date createTime; 14 15 16 @Override 17 protected Object clone() throws CloneNotSupportedException { 18 return super.clone(); 19 } 20 21 public Video() { 22 } 23 24 public Video(String name, Date createTime) { 25 this.name = name; 26 this.createTime = createTime; 27 } 28 29 public String getName() { 30 return name; 31 } 32 33 public void setName(String name) { 34 this.name = name; 35 } 36 37 public Date getCreateTime() { 38 return createTime; 39 } 40 41 public void setCreateTime(Date createTime) { 42 this.createTime = createTime; 43 } 44 45 @Override 46 public String toString() { 47 return "Video{" + 48 "name='" + name + '\'' + 49 ", createTime=" + createTime + 50 '}'; 51 } 52 }
1 /** 2 * @author it-小林 3 * @desc 4 * @date 2021年07月14日 20:16 5 */ 6 public class BCopy { 7 8 public static void main(String[] args) throws CloneNotSupportedException { 9 //原型物件v1 10 Date date = new Date(); 11 Video v1 = new Video("原型模式", date); 12 Video v2 = (Video) v1.clone(); 13 System.out.println("v1=>" + v1); 14 System.out.println("v2=>" + v2); 15 16 System.out.println("======================"); 17 date.setTime(2114422); 18 System.out.println("v1=>" + v1); 19 System.out.println("v2=>" + v2); 20 21 22 //v1 克隆v2 23 //Video v2 = new Video("原型模式", date); 24 /*Video v2 = (Video) v1.clone(); 25 System.out.println("v2=>" + v2); 26 System.out.println("v2=>hash:" + v2.hashCode()); 27 v2.setName("原型模式複製"); 28 System.out.println(v2);*/ 29 } 30 }
執行結果:
(2)深拷貝
1 /** 2 * @author it-小林 3 * @desc 4 * @date 2021年07月14日 20:08 5 * 步驟 6 * 1、實現一個介面 Cloneable 7 * 2、重寫一個方法 clone() 8 */ 9 public class Video implements Cloneable { 10 11 private String name; 12 13 private Date createTime; 14 15 16 @Override 17 protected Object clone() throws CloneNotSupportedException { 18 Object obj = super.clone(); 19 20 Video v = (Video) obj; 21 v.createTime = (Date) this.createTime.clone(); 22 23 return v; 24 } 25 26 public Video() { 27 } 28 29 public Video(String name, Date createTime) { 30 this.name = name; 31 this.createTime = createTime; 32 } 33 34 public String getName() { 35 return name; 36 } 37 38 public void setName(String name) { 39 this.name = name; 40 } 41 42 public Date getCreateTime() { 43 return createTime; 44 } 45 46 public void setCreateTime(Date createTime) { 47 this.createTime = createTime; 48 } 49 50 @Override 51 public String toString() { 52 return "Video{" + 53 "name='" + name + '\'' + 54 ", createTime=" + createTime + 55 '}'; 56 } 57 }
1 /** 2 * @author it-小林 3 * @desc 4 * @date 2021年07月14日 20:16 5 * Spring Bean : 單例模式 原型模式 6 * 原型模式 + 工廠模式 ==》new + 工廠模式 7 * 8 * 9 */ 10 public class BCopy { 11 12 public static void main(String[] args) throws CloneNotSupportedException { 13 //原型物件v1 14 Date date = new Date(); 15 Video v1 = new Video("原型模式", date); 16 Video v2 = (Video) v1.clone(); 17 System.out.println("v1=>" + v1); 18 System.out.println("v2=>" + v2); 19 20 System.out.println("======================"); 21 date.setTime(2114422); 22 System.out.println("v1=>" + v1); 23 System.out.println("v2=>" + v2); 24 25 } 26 }
執行結果:
如本文有侵權行為,請及時與本人聯絡,多多包涵! 小生初出茅廬,多多指教!本文來自部落格園,作者:it-小林,轉載請註明原文連結:https://www.cnblogs.com/linruitao/p/15012715.html