設計模式 —— 創建型模式


創建型模式關注對象的創建過程,它將對象的創建和使用分離,在使用對象時無須知道對象的創建細節,使整個系統的設計更加符合單一職責原則

與之相關的模式有:

  1. 簡單工廠模式(思想重要,但不屬於GoF23種設計模式)
  2. 工廠方法模式
  3. 抽象工廠模式
  4. 建造者模式
  5. 原型模式
  6. 單例模式

1. 簡單工廠模式(Simple Factory)

1.1 定義

又稱靜態工廠方法(Static Factory Method)模式,屬於類創建型模式。
該模式中,專門定義一個工廠類,根據參數的不同來負責創建其他類的實例。

目的:
為了分離對象的創建與使用而生。

1.2模式結構

省略部分關系箭頭,僅保留繼承,為了看着清晰

該模式下包含如下角色:

  1. Factory(工廠角色)
    提供靜態工廠方法,負責創建其他類實例,它返回的是抽象層的產品類,所有具體產品都是抽象產品的子類。

  2. Product(抽象產品角色)
    描述產品實例所具有的接口方法,“客戶使用”以及“工廠返回”都是該抽象產品類型

  3. ConcreteProduct(具體產品角色)
    繼承自抽象產品,實現接口方法

1.3 優缺點

優點:

  1. 客戶無需知道對象具體構建細節,將創建與使用分離,對客戶更加友好,系統更符合單一職責原則。
  2. 因為第1點的分離,若對象構建邏輯有所改變時,只需修改工廠邏輯即可,不用修改所有客戶類。相較於以往,在一定程度上,在“開閉性”上稍有改善。
  3. 抽象產品的引入(雖不一定是模式強制引入的),使系統更加符合依賴倒轉原則。

缺點:

  1. 該單一工廠任務過重,系統擴展困難,一旦需要添加新產品,則不得不修改工廠邏輯,整個系統都可能受影響,不利於擴展和維護,不符合開閉原則。
  2. 增加了類的個數,從某方面來講增加了系統復雜度。

2. 工廠方法模式(Factory Method)

2.1 定義

"Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses."

也稱工廠模式、虛擬構造器模式(Virtual Constructor),或多態工廠模式(Polymorphic Factory),屬於類創造型模式。
該模式,抽象工廠父類定義構建產品對象的公共接口,子工廠則負責創建具體產品對象

目的:
為了彌補簡單工廠模式的不足之處,解決單一工廠職責過重問題,使代碼解耦,符合開閉原則。

簡單理解:繼承了簡單工廠模式優點,彌補了缺點。引入抽象工廠層,具體單個工廠只生產單一產品,客戶面對抽象、接口編程。

2.2 模式結構

  1. Product(抽象產品)
    含義同簡單工廠模式

  2. ConcreteProduct(具體產品)
    某類型具體產品由專門的具體工廠創建,一一對應

  3. Factory(抽象工廠)
    聲明了工廠方法(Factory Method)接口,該方法用於返回產品。

  4. ConcreteFactory(具體工廠)
    繼承或實現抽象工廠,由客戶調用,構建返回某一種具體產品類實例。

2.3 優缺點

優點:
  繼承了簡單工廠模式的優點,並彌補了其缺點。因為抽象工廠層的引入,以及對每種產品生產工廠的分割,使得在增改產品時,只需要添加或改動對應工廠即可,其他代碼不需要做任何修改,使得系統更加依賴倒轉與開閉原則。
注:需通過反射,再配合xml配置文件或IOC來達成,即客戶端不直接new具體工廠,而寫入配置中,可以在一定程度上解耦

缺點:
  每類新產品都需要對應工廠,導致類個數更多增加,某方面來看增加系統復雜度。

3.抽象工廠模式(Abstract Factory Pattern)

3.1 定義

"Provide an interface for creating families of related or dependent object without specifying their concrete classes."
提供一個創建一系列相關或相互依賴對象的接口,而無須指定它們具體的類。

又稱 Kit模式,屬於對象創建型模式。

目的:
當存在多個產品等級結構時,傳統的工廠方法模式的工廠類數量將大量增加。為了解決此問題而生

簡單理解:工廠方法模式只是該模式的特例。該模式中,工廠抽象層不只是定義一個生產單類產品的接口方法,而是用於生產產品族的一組接口方法,比如具體工廠類海爾工廠則實現3個方法,分別生產海爾電視機,海爾冰箱,海爾空調。

相關概念:

  • 產品等級結構:即單類產品的繼承結構。比如一個抽象類是空調,其具體子類為海爾空調,格力空調...,則該抽象空調與每類具體品牌空調之間構成了一個產品等級結構。
  • 產品簇:在抽象工廠模式中,產品簇是指由同一工廠生產的,位於不同產品等級結構的一組產品。如海爾空調,海爾電視機...

3.2 模式結構

  1. AbstractFactory(抽象工廠)
    定義一組用於生成抽象產品對象的方法,每一個方法對應一個產品等級結構
  2. ConcreteFactory(具體工廠)
  3. AbstractProduct(抽象產品)
  4. ConcreteProduct(具體產品)

3.3 優缺點

優點:

  1. 相較於工廠方法模式,減少了類的個數。
  2. 當一個產品族種多個對象被設計成一起工作時,它能保證客戶端始終只使用同一個產品族中的對象。這對一些需要根據當前環境來決定其行為的軟件系統來說,是一種非常使用的設計模式。

缺點:
  因為多產品構建方法糅合到了每個工廠中,導致一定程度上增加了耦合性,導致了開閉原則的“傾斜性”,即若要增加一個產品族,則只需添加一個具體工廠,無須修改其他任何代碼,符合開閉原則;但若想增加一種新產品(產品等級結構),則要添加新接口方法,這將涉及到對抽象工廠及其所有子類的修改,則又不符合開閉原則。

4. 建造者模式(Builder Pattern)

4.1 定義

"Separate the construction of a complex object from its representation so that the same construction process can create different representations."
將復雜對象的構建與它的表示分離,以至於相同的構建過程可以創建不同的表示

又稱生成器模式,屬於對象創建型模式。

目的:
為了解決復雜對象的構建問題。將復雜對象構建步驟分解,並隔離復雜對象創建與使用(或許會想着似乎與工廠相似,但實際有區別的,參照下述理解)

簡單理解:
  對於該模式完整含義,可以通過工廠方法模式來理解,工廠方法模式關注的是單類產品多個不同種類的構建,即不同的具體工廠返回不同種類的產品。而建造者模式,則是關注單個復雜對象的構建,抽象建造者定義"設置產品各個部分或屬性"的接口,而不同的具體建造者通過對相同接口有着不同的實現邏輯,達到對於同種產品有着不同的構建內容。而指揮者則負責安排這些各個部分或屬性接口的調用次序,構建並返回對象給客戶。
達到隔離復雜對象的創建和使用,使得相同創建過程可以創建不同產品(比如,面向抽象編程,再將具體Builder的選擇配置到xml文件中獲取)

若對象各部分(即那些設置屬性的接口方法)構建順序不重要,則完全可以把指揮者合並到建造者里面去,提供一個方法以固定順序構建和返回對象。同理,若系統只需一個具體建造者的話,則也可以省略抽象建造者。

在實際使用中:
  Director角色往往被省略,Builder也作為靜態內部類被放入產品內部(使用靜態的原因,是可以不依賴於外部類實例而被創建),通過使用Builder實例中方法的鏈式調用,來構建產品對象。使得整體更加簡單靈活。

public class ProductObj {
    private final String mName;
    private final String mValue;

    private ProductObj(Builder builder) {
        this.mName = builder.name;
        this.mValue = builder.value;
    }

    public static class Builder {
        private String name;
        private String value;

        public Builder buildName(String nameObj) {
            this.name = nameObj;
            return this;
        }

        public Builder buildValue(String valueObj) {
            this.value = valueObj;
            return this;
        }

        public ProductObj build() {
            return new ProductObj(this);
        }
    }
}

CSDN:Pro_Vinny

4.2 模式結構


以下各角色具體含義,在上文“簡單理解”中已提到,簡單說一下

  1. Builder(抽象建造者)
    定義"設置產品各個部分或屬性"的接口,且可以定義一個產品變量並初始化產品實例,還可以再定義一個返回產品的方法

  2. ConcreteBuilder(具體建造者)
    繼承抽象建造者,不同的具體建造者根據自己業務需求實現上述接口

  3. Product(產品角色)
    復雜對象

  4. Director(指揮者)
    (若接口調用順序不重要則可省略)由客戶端創建,並由傳入的具體建造者,根據一定順序調用其“設置對象屬性”的接口方法,來設置對象,最后返回對象。

4.3 優缺點

  1. 將復雜產品的創建步驟分解在不同方法中,使得創建過程更加清晰,方便控制。
  2. 在原完整定義建造者模式下,不同具體建造者間相互獨立,若想增減時無須修改其他代碼,符合開閉原則。

該模式適用於那些擁有復雜內部結構的產品,且在簡化的情況下,也使得客戶也更能清晰對對象的每一塊進行設置。

5. 原型模式(Prototype Pattern)

5.1 定義

"Specify the kind of objects to create using a prototypical instance, and create new objects by copying this prototype."
用原型實例來確定要創建對象的類型,並通過復制原型來創建新的對象。

屬於對象創建型模式。

目的:
為了簡化多次創建某一類型對象的過程,或保存對象中間狀態。

簡單理解:在原型類中實現克隆方法(從克隆接口或者說抽象原型類繼承的),客戶則需要通過new或者其他方式創建一個原型對象,然后調用克隆方法即可復制得到多個相同對象。

相關概念:

  1. Java對原型模式提供了完美支持,所有類的父類Object中提供並實現了clone()方法(相當於抽象原型類),只需在在子類中將其重寫為public或protected方法,再在其中調用super.clone()即可(因為原方法是protected修飾,只有重寫才能被lang包以外,以及"繼承於Object的具體原型類"以外調用【具體參考java protected修飾知識】),並實現Cloneable接口(標識接口,無具體方法,否則調clone會報異常)即可。注:clone()方法為淺克隆
  2. 淺克隆:克隆對象與原對象本身不是同一個對象,但其中的對象成員變量仍指向相同的值。
  3. 深克隆:把要復制的對象,以及其所引用的對象都復制了一邊。

5.2 模式結構

圖為“帶原型管理器的原型模式”(因為一般原型模式就一個clone方法,沒什么好表示的)

  1. Prototype(抽象原型類)
    定義了克隆自己的方法接口,可以是抽象類或接口。

  2. ConcretePrototype(具體原型類)
    實現了克隆方法,用以復制自身返回一個克隆對象。

  3. Client(客戶類)
    個人感覺該角色沒必要,只要使用的地方都可以算客戶,沒使用也不影響“我”是可克隆的。書上定義的

  4. (可選)Prototype Manager(原型管理器)
    即原型類實例的獲取不再由客戶主動new或者手動調用clone(),而是由原型管理器統一管理。管理器在初始化時,則實例化所有具體原型類,並存入一個集合當中(比如鍵值對的形式)。當客戶需要獲取某個對象克隆時,則調用管理器的獲取方法,該方法根據傳入參數,克隆對應原型對象並返回。

5.3 優缺點

  當需創建對象較為復雜時,或大量重復創建某對象時,可簡化創建過程,提高新實例創建效率。也可適用某些需要保存對象狀態的場合。個人看來無明顯缺點,只是一種模式,需要的時候用即可。(教材上非要與工廠模式相比,說簡化創建結構。個人感覺有些牽強,針對目標使用場景都不同)

6. 單例模式(Singleton Pattern)

6.1 定義

"Ensure a class has only one instance and provide a global point of access to it"
確保一個類只擁有一個實例,且能提供全局訪問的方法。

又稱單件模式或單態模式,屬於對象創建型模式。

目的:
當希望某個類在系統中的實例只存在一個時,可使用該模式

6.2 模式結構

public class LazySingleton {	//懶漢式單例模式
    private static LazySingleton instance = null;

    private LazySingleton(){
    }

    synchronized public static LazySingleton getInstance(){
        if(instance == null)
            instance = new LazySingleton();
        return instance;
    }
}

  該模式只存在一個角色,即單例類本身。單例類中將構造函數私有化,防止外部調用。且定義一個自身靜態成員變量用於存儲實例,然后提供一個靜態工廠方法供外部獲取。而具體自行實例化時機,則分為 餓漢式單例類 以及懶漢式單例類。

相關介紹:

  1. 餓漢式單例類,private static EagerSingleton instance = new EagerSingleton();即,類加載時便實例化自身。
  2. 懶漢式單例類,將實例化延遲到工廠方法被調用時。【注:必須處理好多個線程同時首次引用訪問該方法的問題,因此需要通過同步化機制進行控制】

6.3 優缺點

  將構造函數私有而自行實例化,確保了類實例的唯一性,且可對訪問進行嚴格控制。但因為同時負責創建和業務使用,所以單例類職責過重。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM