# 什么是原型設計模式
> 這里與軟件工程中的原型開發模式有那么一點類似的地方,我們首先需要構建出一個原型,這個原型可以在現實開發中抽象出來的具體類型,但是這個類型與具體的類又不同,需要抽取公共的部分,通過構建管理器,實現創建不同需要的類型,
### 考慮使用原型設計模式的三種情況
第一種情況是需要處理的對象太多,如果將它們分別作為一個類,必須要編寫很多個類文件難以根據類生成實例時
第二種情況是生成實例的過程太過復雜,很難根據類來生成實例。例如,我們假設這里有一個實例,即表示用戶在圖形編輯器中使用鼠標制作出的圖形的實例。想在程序中創建這樣的實例是常困難的,通常,在想生成一個和之前用戶通過操作所創建出的實例完全一樣的實例的時候,我們會事先將用戶通過操作所創建出的實例保存起來,然后在需要時通過復制來生成新的實例想解藕框架與生成的實例時
第三種情況是想要讓生成實例的框架不依賴於具體的類。這時,不能指定類名來生成實例,而要事先“注冊”一個“原型”實例,然后通過復制該實例來生成新的實例。
### 類接口表關系表
包 |
類名 |
描述 |
framework |
manager |
調用createclone |
framework |
product |
聲明use createclone |
naN |
rectangle |
具體打印矩形 |
nan |
triangle |
具體打印三角形 |
Prototype 是由product擔任的
ConcreteProtopyte 實現賦值新實例的方法 由具體的你需要的角色來擔任
Client 通過調用createclone 創建新的實例,由Manger類扮演這個角色
### uml
use 在接口中是交給子類去實現的
createclone 創建具體的對象
- code framework
1 package base.prototype.framework; 2 3 4 5 /** 6 7 * @program: DesignPatterns 8 9 * @description: 聲明use, createclone具體復用 10 11 * @author: Mr.Dai 12 13 * @create: 2018-05-28 21:28 14 15 **/ 16 17 public interface Product extends Cloneable { 18 19 20 21 public abstract void use(int len); 22 23 public abstract Product createClone(); 24 25 }
1 import java.util.HashMap; 2 3 4 5 /** 6 7 * @program: DesignPatterns 8 9 * @description: 產生具體的類,維護多重對象 10 11 * @author: Mr.Dai 12 13 * @create: 2018-05-28 21:31 14 15 **/ 16 17 public class Manager { 18 19 private HashMap<String,Product> warehouse=new HashMap<>(); 20 21 22 23 public void registers(String name,Product product){ 24 25 warehouse.put(name,product); 26 27 } 28 29 30 31 public Product createObj(String name){ 32 33 Product product = warehouse.get(name); 34 35 return product.createClone(); 36 37 } 38 39 }
- code domain 具體的實現的類
1 /** 2 3 * @program: DesignPatterns 4 5 * @description: 打印矩形 6 7 * @author: Mr.Dai 8 9 * @create: 2018-05-28 21:38 10 11 **/ 12 13 public class Rectangle implements Product { 14 15 16 17 private char mark = '*'; 18 19 20 21 public Rectangle(char mark) { 22 23 this.mark = mark; 24 25 } 26 27 28 29 public Rectangle() { 30 31 } 32 33 34 35 @Override 36 37 public void use(int len) { 38 39 for (int i = 0; i < len; i++) { 40 41 if(i==0||i==len-1){ 42 43 for (int k = 0; k < len; k++) System.out.print(mark); 44 45 }else{ 46 47 System.out.print('*'); 48 49 for (int j = 0; j < len-2; j++) { 50 51 System.out.print(' '); 52 53 } 54 55 System.out.print('*'); 56 57 } 58 59 System.out.println(); 60 61 } 62 63 } 64 65 66 67 @Override 68 69 public Product createClone() { 70 71 Product product = null; 72 73 try { 74 75 product = (Product) clone(); 76 77 } catch (CloneNotSupportedException e) { 78 79 e.printStackTrace(); 80 81 } 82 83 return product; 84 85 } 86 87 } 88 89 90 91 import base.prototype.framework.Product; 92 93 94 95 /** 96 97 * @program: DesignPatterns 98 99 * @description: 打印三角形 100 101 * @author: Mr.Dai 102 103 * @create: 2018-05-28 21:47 104 105 **/ 106 107 public class Triangle implements Product { 108 109 110 111 @Override 112 113 public void use(int len) { 114 115 for (int i = 0; i < len; i++) { 116 117 for (int j = i; j < len; j++) { 118 119 System.out.print(' '); 120 121 } 122 123 124 125 for (int j = 0; j < 2*i + 1; j++) { 126 127 System.out.print('*'); 128 129 } 130 131 System.out.println(); 132 133 } 134 135 } 136 137 138 139 @Override 140 141 public Product createClone() { 142 143 Product product=null; 144 145 try { 146 147 product=(Product)clone(); 148 149 }catch (CloneNotSupportedException e){ 150 151 e.printStackTrace(); 152 153 } 154 155 return product; 156 157 } 158 159 } 160 161
- 結果
### 需要說明的是
> 面向對象的根本思想是作為組件復用:一旦出現的類名字就無法與該類區分開來,也就無法實現復用,如果不替換源代碼 以java來說,重要的是當只有class文件的時候還能不能被復用,即使沒有java文件也能夠復用才是關鍵,
>要注意在頂層product 接口聲明 集成的java.lang.cloneable。的接口是稱之為標記接口 只要這樣下面雇用的具體的類才能調用具體的clone方法才不會拋出異常,,說明了 實現了cloneable 接口的實例是可以進行調用clone方法進行復制的,返回是一個新的實例,(clone內部所進行的處理是分配與要復制的實例同樣大小的內存空間,是一盒字段復制 也很稱 淺拷貝);也就是說 如在類中存在 數組 那么拷貝 只會拷貝數組的引用,不會對數組進行正的復制。如果你需要一個新的引用那么你需要 重寫clone ,但是不要忘記 調用super。clone
### 相關設計模式
- Flyweight
prototype可以生成一個與當前實例相同的的實例,使用Flyweight 模式可以在不同的地方使用同一個實例。
- Memento
提供保存當前實例狀態,實現撤銷與快照功能
- Composite 與 Decorator模式
如果需要動態創建復雜的結構的實例,可以用prototype作為clone
- Command
復制Command模式中出現的額命令時,可以使用Prototype