設計模式-創建型之抽象工廠模式

模式動機

       在工廠模式中,具體工廠負責生產具體的產品,每一個具體工廠對應一種具體的產品,但有的時候,我們需要一個工廠可以生產多種產品。爲了闡述的更加清晰明瞭,首先引入兩個抽象工廠模式中概念:產品等級結構和產品族

  • 產品等級結構
    比如一個抽象類是電視機,其子類有長虹電視機,創維電視機,TCL電視機,那麼電視機抽象類與與具體的某個電視機子類便構成了一個產品等級結構,抽象電視機是父類,具體某個品牌的電視機是子類。簡單通俗的來講,可以理解爲同一個產品等級結構,就代表同一類產品,比如電視機可以構成一個產品等級,洗衣機是一個產品等級,電冰箱也是一個產品等級等等

  • 產品族
    在抽象工廠模式中,產品族是指同一個工廠生產的、且屬於不同產品等級結構的一組產品。打個比方,假如有一個創維電器工廠,裏面可以生產創維電視機,創維洗衣機等等,由於電視機跟洗衣機是不同的產品等級,所以整個創維繫列的產品構成了一個產品族。

    總結:產品等級結構可以理解爲同一種分類,不同品牌的產品,而產品族可以理解爲同一種品牌、不同分類的產品。如下圖:
    產品等級和產品族
    在上一篇博客《設計模式-創建型之工廠模式 》中,我們的工廠類只對應了一個產品,如BenzCarFactory負責生產BenzCar,BMWCarFactory負責生產BMWCar。但在現實生活中,奔馳跟寶馬不僅生產轎車,它們其實也生產自行車。套入剛纔的概念可知,轎車跟自行車屬於不同的產品等級結構,而奔馳、寶馬屬於不同的產品族。假設這樣一種情況,現在我們需要構建一個奔馳工廠,裏面既可以生產奔馳汽車,也可以生產奔馳自行車,還有一個寶馬工廠,裏面既可以生產寶馬汽車,也可以生產寶馬自行車。這便是我們的抽象工廠模式!

模式定義

       提供一個創建一系列相關或相互依賴對象的接口,而無須指定它們具體的類,抽象工廠模式也叫Kit模式。其實也很簡單,就是在工廠模式的基礎上進行了增強,讓其更加具有通用性,一般性。工廠模式中工廠類只負責一種產品的創建工作,在抽象工廠模式中,一個工廠可以生產多種產品,這些產品都屬於同一個產品族。

模式結構

模式結構
       工廠模式主要由以下四部分組成:
  抽象工廠:抽象出工廠所需屬性或行爲,如IFactory
  具體工廠:具體的某個工廠類,負責創建某個具體的產品,如BenzFactory,BMWFactory
  抽象產品:抽象出產品所需屬性或行爲,ICar,IBike
  具體產品:具體的某個產品,如BenzCar,BMWCar,BenzBike,BMWBike

代碼實現

抽象工廠類

public interface IFactory {
    public abstract ICar createCar();
    public abstract IBike createBike();
}

  具體工廠類

public class BenzFactory implements IFactory{

    @Override
    public ICar createCar() {
        return new BenzCar();
    }

    @Override
    public IBike createBike() {
        return new BenzBike();
    }
}
public class BMWFactory implements IFactory{

    @Override
    public ICar createCar() {
        return new BMWCar();
    }

    @Override
    public IBike createBike() {
        return new BMWBike();
    }
}

  抽象產品類

public interface ICar {
    public abstract String getName();
}
public interface IBike {
    public abstract String getName();
}

  具體產品類

public class BMWBike implements IBike {
    @Override
    public String getName() {
        return "寶馬Bike";
    }
}
public class BMWCar implements ICar {
    @Override
    public String getName() {
        return "寶馬Car";
    }
}
public class BenzBike implements IBike {
    @Override
    public String getName() {
        return "奔馳Bike";
    }
}
public class BenzCar implements ICar {
    @Override
    public String getName() {
        return "奔馳Car";
    }
}

  客戶端測試類

public class Client {
    public static void main(String[] args) {
        IFactory factory1 = new BenzFactory();
        IFactory factory2 = new BMWFactory();
        ICar car1 = factory1.createCar();
        IBike bike1 = factory1.createBike();
        ICar car2 = factory2.createCar();
        IBike bike2 = factory2.createBike();
        System.out.println(car1.getName());
        System.out.println(bike1.getName());
        System.out.println(car2.getName());
        System.out.println(bike2.getName());
    }
}

  運行客戶端測試類,輸出爲

奔馳Car
奔馳Bike
寶馬Car
寶馬Bike

模式優缺點

優點

  • 抽象工廠模式隔離了具體類的生成,使得客戶並不需要知道什麼被創建。由於這種隔離,更換一個具體工廠就變得相對容易,因爲所有的具體工廠都實現了抽象工廠中定義的那些公共接口,因此只需改變具體工廠的實例,就可以在某種程度上改變整個軟件系統的行爲。比如我們的例子中,如果想把生產奔馳這個產品系列修改爲生產寶馬系列。那麼只需要將IFactory factory1 = new BenzFactory()修改爲IFactory factory1 = new BMWFactory()即可。這裏我們只是方便測試,寫得很簡單。在實際開發中,完全可以將我們的工廠配置在xml、property等配置文件中,然後通過java的反射機制對具體工廠進行實例化,所以我們只需要修改一下配置文件,就可以達到修改整個產品系列的效果
  • 當一個產品族中的多個對象被設計成一起工作時,它能夠保證客戶端始終只使用同一個產品族中的對象
  • 增加新的產品族很方便,只需要新增相應的具體工廠類和具體產品類即可。比如現在我們需要新增一個奧迪工廠,用於生產奧迪汽車和奧迪自行車,則只需要新增AudiFactory,AudiCar,AudiBike即可,無需修改之前的代碼。

缺點

  • 在添加新的產品對象時,難以擴展抽象工廠來生產新種類的產品,這是因爲在抽象工廠角色中規定了所有可能被創建的產品集合,要支持新種類的產品就意味着要對該接口進行擴展,而這將涉及到對抽象工廠角色及其所有子類的修改,顯然會帶來較大的不便。比如在我們的例子中,現在需要新增一個“摩托車”產品。那麼我們則需要修改IFactory,添加createMotorcycle()方法,BMWFactory跟BenzFactory也需要增加該方法。這樣顯然是改動很大的。

開閉原則的傾斜性

       根據抽象模式的優缺點可以看出,增加產品族是無需修改已有代碼的,很好的支持了開閉原則,但新增新的產品等級結構時,則需要修改抽象工廠類及其子類,違背了開閉原則。抽象工廠模式這種性質我們成爲“開閉原則的傾斜性”

適用場景

  • 一個系統不依賴於產品類實例如何被創建、組合和表達的細節。這是所有工廠類型模式的前提
  • 系統中有多於一個的產品族,而每次只使用其中某一產品族
  • 屬於同一個產品族的產品需要在一起使用時
  • 系統提供一個產品類的庫,所有的產品以同樣的接口出現,客戶端不依賴於某個具體的實現

總結

       抽象工廠模式稍微要比工廠模式複雜一些,但其實也複雜不了多少。簡單理解下,無非就是工廠模式中的工廠只生產一種產品,而抽象工廠模式中的工廠是生產多個產品,即一個產品族。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章