本人學習筆記。內容參考《Java設計模式》劉偉 教程配套PPT。僅供學習參考使用。
總述
創建型模式關注對象的創建過程。對類的實例化過程進行了抽象,能夠將軟件模塊中對象的創建和對象的使用分離,對用戶隱藏了類的實例的創建細節。
創建型模式描述如何將對象的創建和使用分離,讓用戶在使用對象時無須關心對象的創建細節,從而降低系統的耦合度,讓設計方案更易於修改和擴展。
創建型模式有6種,下面的表格我總結了它們的定義和例子:
模式名稱 | 定義 | 形象化例子 | 應用實例 |
---|---|---|---|
簡單工廠模式 | 定義一個工廠類,它可以根據參數的不同返回不同類的實例,被創建的實例通常都具有共同的父類。 | 農場種瓜得瓜 | 提供多種不同外觀的圖表的圖表庫 |
工廠方法模式 | 定義一個用於創建對象的接口,但是讓子類決定將哪一個類實例化。工廠方法模式讓一個類的實例化延遲到其子類。 | 一個工廠生產一樣產品 | 通過多種途徑保存日誌的日誌記錄器 |
抽象工廠模式 | 提供一個創建一系列相關或相互依賴對象的接口,而無須指定它們具體的類。 | 一個工廠生產一種風格的系列產品 | 提供不同風格界面的皮膚庫 |
建造者模式 | 將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。 | 生產汽車不用管零部件 | 有多個屬性的遊戲角色 |
原型模式 | 使用原型實例指定待創建對象的類型,並且通過複製這個原型來創建新的對象。 | 孫悟空拔毛 | 快速創建相同或者相似的週報 |
單例模式 | 確保一個類只有一個實例,並提供一個全局訪問點來訪問這個唯一實例。 | Windows任務管理器 | 負責管理和請求的分發的服務器負載均衡器 |
1.簡單工廠模式
概述
定義一個工廠類,它可以根據參數的不同返回不同類的實例,被創建的實例通常都具有共同的父類。
如果需要什麼,只需要傳入一個正確的參數,就可以獲取所需要的對象,而無須知道其創建細節。
結構
客戶端需要產品A,則告知工廠並獲得抽象產品,工廠生產具體的產品A而返回。
優缺點
優點:
- 實現了對象創建和使用的分離。
- 客戶端無須知道所創建的具體產品類的類名,只需要知道具體產品類所對應的參數即可。
- 通過引入配置文件,可以在不修改任何客戶端代碼的情況下更換和增加新的具體產品類,在一定程度上提高了系統的靈活性。
缺點:
- 工廠類集中了所有產品的創建邏輯,一旦不能正常工作,整個系統都要受到影響。
- 增加系統中類的個數(引入了新的工廠類),增加了系統的複雜度和理解難度。
- 不滿足開閉原則。系統擴展困難,一旦添加新產品不得不修改工廠邏輯。
- 由於使用了靜態工廠方法,造成工廠角色無法形成基於繼承的等級結構,工廠類不能得到很好地擴展。
2.工廠方法模式
概述
定義一個用於創建對象的接口,但是讓子類決定將哪一個類實例化。工廠方法模式讓一個類的實例化延遲到其子類。
工廠父類負責定義創建產品對象的公共接口,而工廠子類則負責生成具體的產品對象。目的是將產品類的實例化操作延遲到工廠子類中完成,即通過工廠子類來確定究竟應該實例化哪一個具體產品類。
結構
客戶端需要產品A,則告知抽象工廠並獲得抽象產品,抽象工廠告知A具體工廠,A具體工廠生產具體的產品A而返回。注意,抽象工廠、抽象產品是接口(或父類)。
優缺點
優點:
- 工廠方法用來創建客戶所需要的產品,同時還向客戶隱藏了哪種具體產品類將被實例化這一細節。能夠讓工廠自主確定創建何種產品對象,而如何創建這個對象的細節則完全封裝在具體工廠內部。
- 在系統中加入新產品時,完全符合開閉原則。
缺點:
- 系統中類的個數將成對增加,在一定程度上增加了系統的複雜度,會給系統帶來一些額外的開銷。增加了系統的抽象性和理解難度。
3.抽象工廠模式
概述
提供一個創建一系列相關或相互依賴對象的接口,而無須指定它們具體的類。
抽象工廠模式中的具體工廠不只是創建一種產品,它負責創建一族產品。當一個工廠等級結構可以創建出分屬於不同產品等級結構的一個產品族中的所有對象時,抽象工廠模式比工廠方法模式更爲簡單、更有效率(工程方法每個具體工廠只有一個或者一組重載的工廠方法,只能生產一種產品)。
經典例子:皮膚庫,有不同的皮膚,每種皮膚有相同風格的多個元件。(不同皮膚元件種類相同)
結構
客戶需要風格A的一組產品,那麼從抽象工廠獲得一系列抽象產品,抽象工廠讓具體工廠A生成A風格的一系列產品而返回。
優缺點
優點:
- 隔離了具體類的生成,使得客戶端並不需要知道什麼被創建。
- 當一個產品族中的多個對象被設計成一起工作時,它能夠保證客戶端始終只使用同一個產品族中的對象。
- 增加新的產品族(風格)很方便,無須修改已有系統,符合開閉原則。
缺點:
- 增加新的產品等級結構(組件)麻煩,需要對原有系統進行較大的修改,甚至需要修改抽象層代碼,違背開閉原則。
4.建造者模式
概述
將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
建造者模式可以將部件本身和它們的組裝過程分開,關注如何一步步創建一個包含多個組成部分的複雜對象,客戶端無須知道複雜對象的內部組成部分與裝配方式,只需要知道所需建造者的類型即可。
經典例子:建造有多個組成部分且不同產品組成部分一樣的複雜產品,如汽車、遊戲角色。
結構
客戶端讓抽象建造者建造產品A,抽象建造者讓具體建造者A建造不同的部分,組成產品A而返回。
優缺點
優點:
- 客戶端不必知道產品內部組成的細節,將產品本身與產品的創建過程解耦,使得相同的創建過程可以創建不同的產品對象。
- 每一個具體建造者都相對獨立,與其他的具體建造者無關,因此可以很方便地替換具體建造者或增加新的具體建造者,擴展方便,符合開閉原則。
- 可以更加精細地控制產品的創建過程。
缺點:
- 如果產品之間的差異性很大,不適合使用建造者模式,因此其使用範圍受到一定的限制。
- 如果產品的內部變化複雜,可能會需要定義很多具體建造者類來實現這種變化,導致系統變得很龐大,增加了系統的理解難度和運行成本。
5.原型模式
概述
使用原型實例指定待創建對象的類型,並且通過複製這個原型來創建新的對象。
要發動創建的對象通過請求原型對象複製後者自己來實現創建過程。創建克隆對象的工廠就是原型類自身,工廠方法由負責複製原型對象的克隆方法來實現。通過克隆方法所創建的對象是全新、獨立的對象,它們在內存中擁有新的地址。通過不同的方式對克隆對象進行修改以後,可以得到一系列相似但不完全相同的對象。
克隆分淺克隆和深克隆,區別在對象包含的成員變量是否被複制(複製地址或新建)。
可增加一個原型管理器,將多個原型對象存儲在一個集合中供客戶端使用。
結構
將一個原型對象傳給客戶端對象,客戶端對象通過請求原型對象複製自己來實現創建過程。
優缺點
優點:
- 簡化對象的創建過程,通過複製一個已有實例可以提高新實例的創建效率。
- 擴展性較好。
- 提供了簡化的創建結構,無須專門的工廠類來創建產品。
- 可以使用深克隆的方式保存對象的狀態,需要的時候可輔助實現撤銷操作。
缺點:
- 需要爲每一個類配備一個克隆方法,而且該克隆方法位於一個類的內部,當對已有的類進行改造時,需要修改源代碼,違背了開閉原則。
- 在實現深克隆時需要編寫較爲複雜的代碼。
6.單例模式
概述
確保一個類只有一個實例,並提供一個全局訪問點來訪問這個唯一實例。
某個類只能有一個實例。必須自行創建這個實例。必須自行向整個系統提供這個實例。
經典例子:任務管理器、回收站。
結構
單例模式只包含一個單例角色。聚合自己。
餓漢式單例模式:
無須考慮多個線程同時訪問的問題;調用速度和反應時間優於懶漢式單例;資源利用效率不及懶漢式單例;系統加載時間可能會比較長。
public class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() { }
public static EagerSingleton getInstance() {
return instance;
}
}
懶漢式單例模式:
實現了延遲加載;必須處理好多個線程同時訪問的問題;需通過雙重檢查鎖定等機制進行控制,將導致系統性能受到一定影響。
public class LazySingleton {
private volatile static LazySingleton instance = null;
private LazySingleton() { }
public static LazySingleton getInstance() {
//第一重判斷
if (instance == null) {
//鎖定代碼塊
synchronized (LazySingleton.class) {
//第二重判斷
if (instance == null) {
instance = new LazySingleton(); //創建單例實例
}
}
}
return instance;
}
}
優缺點
優點:
- 提供了對唯一實例的受控訪問。
- 可以節約系統資源,提高系統的性能。
缺點:
- 缺少抽象層,擴展困難。
- 例類的職責過重。
- 由於自動垃圾回收機制,可能會導致共享的單例對象的狀態丟失。
練習
分別用簡單工廠模式、工廠方法模式、抽象工廠模式、建造者模式設計一個簡單的畫圖板(繪製直線、長方形、圓等),每個要求類似,每個都體現了這種模式的功能。(未完待續)
UML圖如下: