文章目錄
設計模式——創建型模式
單例模式
概念:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點
實現一:餓漢模式
餓漢在類加載時就完成了初始化,避免了多線程同步的問題,如果始終沒有使用這個實例,就會造成內存浪費。
實現二:懶漢模式(線程不安全)
懶漢模式聲明瞭一個靜態對象,在用戶第一次調用時初始化。在多線程時不能正常工作。
實現三:懶漢模式(線程安全)
這種寫法在多線程中可以很好的工作,但是每次調用getInstance方法都需要同步,造成不必要的時間開銷。
實現四:雙重檢查模式(DCL)
在方法內部進行了兩次判空,第一次爲了不必要的同步,第二次是在實例等於null的時候才創建,其真實目的是爲了防止jvm的指令重排,但是在。
實現五:靜態內部單例模式
第一次加載Singleton時,並不會初始化sInstance,只有在第一次調用getInstance方法時虛擬機加載SingletonHolder並初始化SInstance。這樣保證了線程安全,也能保證Singleton類的唯一性。
實現六:枚舉單例
默認枚舉單例創建是線程安全的。並且在任何情況先都是單例。
上面的單例模式中有一種情況會重新創建對象——反序列化
將一個單例實例對象寫到磁盤再讀回來,從而獲得了一個實例。
反序列化操作提供了readResolve方法,這個方法可以讓開發人員控制對象的反序列化。在上述幾個方法示例中,如果要杜絕單例對象被反序列化時重新生成對象。就需要加入如上代碼。
實現七:容器實現
class SingletonManager {
private static Map<String, Object> objectMap = new HashMap<>();
private SingletonManager() {}
public static void registerService(String key, Object instance) {
if (!objectMap.containsKey(key)) {
objectMap.put(key, instance);
}
}
public static Object getService(String key) {
return objectMap.get(key);
}
}
將多種單例類注入到一個統一的管理類中,在使用是通過key獲取對應類型的對象。
使用場景
在一個系統中,要求一個類有且僅有一個對象,它的具體使用場景如下:
- 整個項目需要一個共享訪問點或共享數據。
- 創建一個對象需要耗費的資源過多,比如訪問I/O或者數據庫等資源。
- 工具類對象。
簡單工廠模式
又叫靜態工廠方法模式。
簡單工廠模式,其屬於創建型設計模式,但是並不屬於 23種GoF設計模式之一。提到它是爲了讓大家能夠更好地理解後面講到的工廠方法模式。
在簡單工廠模式中有如下角色。
- Factory:工廠類,這是簡單工廠模式的核心,它負責實現創建所有實例的內部邏輯。工廠類的創建產品類的方法可以被外界直接調用,創建所需的產品對象。
- IProduct:抽象產品類,這是簡單工廠模式所創建的所有對象的父類,它負責描述所有實例所共有的公共接口。
- Product:具體產品類,這是簡單工廠模式的創建目標。
簡單實現
我們用生產計算機來舉例,假設有一個計算機的代工生產商,它目前已經可以代工生產聯想計算機了。隨着業務的拓展,這個代工生產商還要生產惠普和華碩的計算機。這樣我們就需要用一個單獨的類來專門生產計算機,這就用到了簡單工廠模式。下面我們來實現簡單工廠模式。
抽象產品類Computer
具體產品類
創建各個品牌的計算機,其都繼承了自己的父類Computer,並實現了父類的start方法。具體的計算機產品分別是聯想、惠普和華碩計算機:
工廠類
創建一個工廠類,它提供了一個靜態方法 createComputer 用來生產計算機。你只需要傳入自己想生產的計算機的品牌,它就會實例化相應品牌的計算機對象,代碼如下所示:
客戶端調用
客戶端調用工廠類,傳入"hp"生產出惠普計算機並調用該計算機對象的 start 方法
使用場景及優缺點
使用場景
- 工廠類負責創建的對象比較少。
- 客戶只需知道傳入工廠類的參數,而無須關心創建對象的邏輯。
優點
- 使用戶根據參數獲得對應的類實例,避免了直接實例化類,降低了耦合性。
缺點
- 可實例化的類型在編譯期間已經被確定。如果增加新類型,則需要修改工廠,這違背了開放封閉原則。簡單工廠需要知道所有要生成的類型,其當子類過多或者子類層次過多時不適合使用。
工廠方法模式
定義一個用於創建對象的接口,讓子類決定實例化哪個類。工廠方法使一個類的實例化延遲到其子類。
工廠方法模式中有以下角色:
- Product:抽象產品類。
- ConcreteProduct:具體產品類,實現Product接口。
- Factory:抽象工廠類,該方法返回一個Product類型的對象。
- ConcreteFactory:具體工廠類,返回ConcreteProduct實例。
簡單實現
工廠方法模式的抽象產品類與具體產品類的創建和簡單工廠模式是一樣的,具體在上面簡單工廠。
創建抽象工廠:
抽象工廠裏面有一個 createComputer 方法,想生產哪個品牌的計算機就生產哪個品牌的。
具體工廠
廣達代工廠是一個具體的工廠,其繼承抽象工廠,通過反射來生產不同廠家的計算機:
客戶端調用
客戶端創建了GDComputerFactor,並分別生產了聯想、惠普和華碩計算機:
簡單工廠和工廠方法
對於簡單工廠,我們在工廠類中進行了必要的邏輯判斷,根據不同的條件實例化相關的類。
除去了客戶端與具體產品的依賴,但是帶來了一個問題:如果我們需要添加產品就需要修改我們的工廠類,這違背了開放封閉原則。
而工廠方法模式就沒有違背這個開放封閉原則。如果我們需要生產蘋果計算機,則無須修改工廠類,直接創建產品即可。
建造者模式
將一個複雜的對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
它允許用戶不知道內部構建細節的情況下,可以精細的控制構造流程。
在建造者模式中有如下角色
- Director:導演類,負責安排已有模塊的順序,然後通知Builder開始建造。
- Builder:抽象Builder類,規範產品的組建,一般由子類實現。
- ConcreteBulider:具體建造者,實現抽象 Builder 類定義的所有方法,並且返回一個組建好的對象。
- Product:產品類。
簡單實現
用DIY組裝計算機的例子來實現一下建造者模式。
創建產品類
組裝一臺計算機,計算機被抽象爲Computer類,它有3個部件:CPU、主板和內存,並在裏面提供了3個方法分別用來設置CPU、主板和內存:
創建Builder類規範產品的組建
商家組裝計算機有一套組裝方法的模板,就是一個抽象的 Builder 類,其裏面提供了安裝CPU、主板和內存的方法,以及組裝成計算機的create方法
商家實現了抽象的Builder類,MoonComputerBuilder類用於組裝計算機
用導演類來統一組裝過程
商家的導演類用來規範組裝計算機的流程規範,先安裝主板,再安裝CPU,最後安裝內存並組裝成計算機:
客戶端調用導演類
最後商家用導演類組裝計算機。我們只需要提供自己想要的CPU、主板和內存就可以了,至於商家怎樣組裝計算機我們無須知道
使用場景及優缺點
使用場景
- 當創建複雜對象的算法應該獨立於該對象的組成部分以及它們的裝配方式時。
- 相同的方法,不同的執行順序,產生不同的事件結果時。
- 多個部件或零件都可以被裝配到一個對象中,但是產生的運行結果又不相同時。
- 產品類非常複雜,或者產品類中的調用順序不同而產生了不同的效能。
- 在創建一些複雜的對象時,這些對象的內部組成構件間的建造順序是穩定的,但是對象的內部組成構件面臨着複雜的變化。
優點
- 使用建造者模式可以使客戶端不必知道產品內部組成的細節。
- 具體的建造者類之間是相互獨立的,容易擴展。
- 由於具體的建造者是獨立的,因此可以對建造過程逐步細化,而不對其他的模塊產生任何影響。
缺點
- 產生多餘的Build對象以及導演類。