1. 程式人生 > >設計模式 c++版(5)——抽象工廠模式

設計模式 c++版(5)——抽象工廠模式

定義:為建立一組相關或相互依賴的物件提供一個介面,而且無需指定它們的具體類

示例一:女媧造人擴充套件

造出來黑、白、黃種人,分別有性別分類 類圖說明:一個介面,多個抽象類,N個實現類,每個人種都是一個抽象類,性別是在各個實現類中實現的。

1. 結構說明:

HumanFactory 介面,這個介面中定義了三個方法,分別用來產生三個不同膚色的人種FemalFactory 和 MaleFactory 兩個實現類,實現膚色、性別定義AbstractBlackHuman 每個抽象類都有兩個實現類,分別實現公共的、最具體的事物:膚色和語言。

2. 女媧造人類圖9-2:

3. 女媧造人,程式碼清單9-2:  

#include <QCoreApplication>
#include <QDebug>

//////    **********  1. 女媧造人擴充套件,程式碼清單9-1:***************//


class Human
{
public:
    virtual void    getColor() = 0;
    virtual void    talk()     = 0;
    virtual void    getSex()   = 0;
};

class YellowHuman:public Human
{
public:
    virtual void    getColor()  {qDebug() << "YellowHuman color: yellow";}
    virtual void    talk()      {qDebug() << "YellowHuman talk: ccc";}    
};

class FYellowHuman:public YellowHuman 
{
public:
    virtual void    getSex()    {qDebug() << "*FemalYellowHuman*";} 
};

class HumanFactory
{
public:
    virtual Human* createYellowHuman() = 0;
};

class FemalFactory:public HumanFactory
{
public:
    virtual Human* createYellowHuman() 
    {  
        FYellowHuman *hu = new FYellowHuman();
        Human *human = dynamic_cast<Human*>(hu);
        return human;
    }
};

int main()
{
    FemalFactory factory;
    
    Human *human = factory.createYellowHuman();
    human->getSex();
    human->getColor();
    human->talk();
    
    return 0;
}

4. 這裡只寫出了製造女性黃種人的示例程式碼,其他類同

示例二:通用抽象工廠模式

1. 抽象工廠模式通用類圖,類圖9-3

說明:抽象工廠模式是工廠模式的升級版本,在有多個業務品種、業務分類時,通過抽象工廠模式產生需要的物件是一種非常好的解決方式。

2. 抽象工廠模式通用原始碼類圖,類圖9-4

說明:有兩個相互影響的產品線(也叫做產品族),例如製造汽車的左側門和右側門,這兩個應該是數量相等的——兩個物件之間的約束,每個型號的車門都是不一樣的,這是產品等級結構約束的。

3. 通用抽象工廠模式,程式碼清單9-2:  

#include <QCoreApplication>
#include <QDebug>

//////    **********  2.抽象工廠模式的通用原始碼 ,程式碼清單9-1:***************//

//ProductA
class AbstractProductA
{
public:
    void            shareMethod(){}
    virtual void    doSomething() = 0;
};

class ProductA1:public AbstractProductA
{
public:
    virtual void    doSomething(){qDebug() << "ProductA1 method";}
};

class ProductA2:public AbstractProductA
{
public:
    virtual void    doSomething(){qDebug() << "ProductA2 method";}
};

//ProductB
class AbstractProductB
{
public:
    void            shareMethod(){}
    virtual void    doSomething() = 0;
};

class ProductB1:public AbstractProductB
{
public:
    virtual void    doSomething(){qDebug() << "ProductB1 method";}
};

class ProductB2:public AbstractProductB
{
public:
    virtual void    doSomething(){qDebug() << "ProductB2 method";}
};

//Creator
class AbstractCreator
{
public:
    virtual AbstractProductA* createProductA() = 0;
    virtual AbstractProductB* createProductB() = 0;
};

class Creator1:public AbstractCreator
{
public:
    virtual AbstractProductA* createProductA()
    {
        ProductA1 *a1 = new ProductA1();
        AbstractProductA *product = dynamic_cast<AbstractProductA*>(a1);
        return product;
    }

    virtual AbstractProductB* createProductB()
    {
        ProductB1 *b1 = new ProductB1();
        AbstractProductB *product = dynamic_cast<AbstractProductB*>(b1);
        return product;
    }
};

class Creator2:public AbstractCreator
{
public:
    virtual AbstractProductA* createProductA()
    {
        ProductA2 *a2 = new ProductA2();
        AbstractProductA *product = dynamic_cast<AbstractProductA*>(a2);
        return product;
    }

    virtual AbstractProductB* createProductB()
    {
        ProductB2 *b2 = new ProductB2();
        AbstractProductB *product = dynamic_cast<AbstractProductB*>(b2);
        return product;
    }
};

int main ()
{
    Creator1 creator1;
    Creator2 creator2;
    
    AbstractProductA *a1 = creator1.createProductA();
    AbstractProductA *a2 = creator2.createProductA();
    
    AbstractProductB *b1 = creator1.createProductB();
    AbstractProductB *b2 = creator2.createProductB();
    
    a1->doSomething();
    a2->doSomething();
    b1->doSomething();
    b2->doSomething();
    
    return 0;
}




說明:場景類中,沒有任何一個方法與實現類有關,對於一個產品來說,我們只要知道他的工廠方法就可以直接產生一個產品隊形,無需關心他的實現類。

三、工廠方法模式的應用

優點:

  •  封裝性。每個產品的實現類不是高層模組要關心的,它要關心的是介面。只要知道工廠類,就可以創建出一個需要的物件。
  •  產品族內的約束為非公開狀態。具體的產品族內的約束是在工廠內實現的

  缺點:

 產品族擴充套件非常困難。以通用程式碼為例,如果要增加一個產品C,抽象類 AbstractCreator 要增加一個方法 createProductC() ,另外兩個實現類都需要修改,違反了開閉原則。

使用場景:

一個物件族(或是一組沒有任何關係的物件)都有相同的約束,則可以使用抽象工廠模式。 例如:一個文字編輯器和一個圖片處理器,都是軟體實體,但是在*nix 下的文字編輯器和 windows 下的文字編輯器雖然功能和介面都相同,但是程式碼實現不同,圖片處理器也有類似情況。也就具有了共同的約束條件:作業系統型別。於是我們可以使用抽象工廠模式,產生不同作業系統下的編輯器和圖片處理器。

注意事項:

在抽象工廠模式的缺點中,我們提到抽象工廠模式的產品族擴充套件比較困難,但是產品等級容易擴充套件。只要增加一個工廠類負責新增加出來的產品生產任務即可。也就是說橫向擴充套件容易,縱向擴充套件困難。以女媧造人為例,產品登記彙總只有男、女兩個性別,需要再增加雙性人,吶我們需要增加咱哥產品類,分別對應不同的膚色,然後再建立一個工廠類,專門負責不同膚色人的雙性人的建立任務,完全通過擴充套件來實現需求的變更,從這一點上看,抽象工廠模式符合開閉原則。

四、最佳實踐

在軟體產品開發過程中,涉及不同作業系統的時候,都可以考慮使用抽象工廠模式。例如一個應用,需要再三個不同平臺(windows 、linux 、android)上執行,可以通過抽象工廠模式遮蔽掉作業系統對應用的影響。三個不同作業系統上的軟體功能、應用邏輯、UI都應該是非常類似的,唯一不同的是呼叫不同的工廠方法,由不同的產品類去處理與作業系統互動的資訊。

參考文獻《秦小波. 設計模式之禪》(第2版) (華章原創精品) (Kindle 位置 308-310). 機械工業出版社