常用設計模式之 - 工廠設計模式(簡單工廠、工廠方法、抽象工廠)

    工廠模式是最常用的創建型模式之一,在開始工廠模式之前,我們先來看一個場景,假如要設計一個電腦類,生成的電腦對象要包含CPU,那麼可能有人會這麼設計:

class PC
{
private:
    string m_CPU;
public:
    PC(string nPCName)
    {
        if("Apple" == nPCName)
        {
            m_CPU = "Apple_CPU";
        }
        else if("Dell" == nPCName)
        {
            m_CPU = "Dell_CPU";
        }
    }

    string getCPU()
    {
        return m_CPU;
    }
};

這裏舉的例子中假設蘋果電腦用自己CPU,戴爾電腦用自己的CPU(當然也可能是第三方的CPU),然後按照下邊的方式使用

int main(int argc, char* argv[])
{
    PC ApplePC("Apple");
    cout << ApplePC.getCPU() << endl;

    return 0;
}

可以得到輸出的CPU是蘋果的,但是這裏個問題是,假如有一天要生成HP電腦,那麼我們就必須要改PC類,在裏邊增加else if("HP" == nPCName){HP電腦初始化},這就導致了每增加一個電腦品牌,都要在PC類中做修改,這違背了設計模式中的開閉原則。

      爲了解決上面的問題,我們引出標題中的簡單工廠模式,在簡單工廠模式中,我們要引入三個角色:
      1、Factory(工廠角色):工廠角色是簡單工廠模式的核心,負責創建所有產品實例,返回的是抽象產品類型(見第2點)
      2、Product(抽象產品角色):作爲所有產品類的父類封裝了產品類的共有方法。
      3、ConcreteProduct(具體產品角色):繼承自抽象產品角色而創建的實實在在的目標,並實現了抽象產品角色中的共有方法。

有了以上三點,我們來改造下我們的代碼:
首先創建一個電腦的產品類(包括PC抽象類、PC具體類),抽象類中接口爲獲取CPU的純虛函數

//PC的抽想產品類
class PC
{
public:
    virtual string getCPU() = 0;
};

//具體PC類:Apple電腦,繼承自PC抽象類
class ApplePC : public PC
{
public:
    string getCPU()
    {
        return "AppleCPU";
    }
};

//具體PC類:Dell電腦,繼承自PC抽象類
class DellPC : public PC
{
public:
    string getCPU()
    {
        return "DellCPU";
    }
};

接着來創建簡單工廠的核心部分:工廠類(要點爲返回的值爲抽象產品類,才能實現多態)

class PCFactory
{
public:
    //這裏設爲靜態函數的目的是可以直接通過類名::createPC調用,不需要實例化工廠對象
    //需要注意的是:返回值爲產品的抽象類(這裏爲電腦抽象類PC)
    static PC* createPC(string nPCName)
    {
        if("Apple" == nPCName)
        {
            return new ApplePC;
        }
        else if("Dell" == nPCName)
        {
            return new DellPC;
        }
    }
};

到這裏,我們的簡單工廠模式已經設計完成,使用如下:

int main(int argc, char* argv[])
{
    PC* pPC = PCFactory::createPC("Apple");

    cout << pPC->getCPU() << endl;

    return 0;
}

簡單工廠模式在一定程度上解決了問題, 但是細心的朋友會發現,當我們需要增加HP電腦時,就需要更改PCFactory工廠類中的方法,也就是說每次更改增加一個電腦,就要重新編譯客戶端的工廠類。

導致 這個問題的原因就是:簡單工廠模式所有的產品都由同一個工廠生產,那有沒有可能是設置一個只負責下命名的總工廠,而生產產品的工作由各個子工廠完成,答案是肯定的,這就是即將要說的工廠模式。其實這 跟企業的管理模式有異曲同工之妙,總部只負責下達命令我要生產什麼,具體生產執行則由各個工廠去完成。

    現在來看看工廠模式需要的幾個要素
       1、Factory(抽象工廠角色):抽象工廠角色是工廠模式的核心,聲明公共的創建方法(即指令),具體工廠要繼承抽象工廠並實現接口。
       2、ConcreteFactory(具體工廠角色):繼承抽象工廠,實現創建接口創建具體的產品
       3、Product(抽象產品角色):作爲所有產品類的父類封裝了產品類的共有方法。
       4、ConcreteProduct(具體產品角色):繼承自抽象產品角色而創建的實實在在的目標,並實現了抽象產品角色中的共有方法。

//抽象產品(電腦)
class PC
{
public:
    virtual string getCPU() = 0;
};

//具體產品(Apple電腦)
class ApplePC : public PC
{
public:
    string getCPU()
    {
        return "AppleCPU";
    }
};

//具體產品(Dell電腦)
class DellPC : public PC
{
public:
    string getCPU()
    {
        return "DellCPU";
    }
};

//抽象工廠(工廠總部)
class Factory
{
public:
    virtual PC* createPC() = 0;
};

//具體工廠(Apple工廠)
class AppleFactory : public Factory
{
public:
    PC* createPC()
    {
        return new ApplePC;
    }
};

//具體工廠(Dell工廠)
class DellFactory : public Factory
{
public:
    PC* createPC()
    {
        return new DellPC;
    }
};


int main(int argc, char* argv[])
{
    Factory* f = new DellFactory; //下達指令到Dell工廠(要生產Dell電腦)
    PC* pPC = f->createPC();      //Dell工廠生產電腦

    cout << pPC->getCPU() << endl; //使用具體的產品

    return 0;
}

到這,工廠模式就結束了,但是需求會回來越多,假如我要使用電腦、手機兩個設備連成一個家庭套餐使用。那就有可能不同品牌間的手機電腦無法正常連接或者使用體驗不好。比方我們用的電腦時Apple的,但是手機是HW,那麼他們的使用體驗可能就不那麼友善了。


    爲了解決這個問題,我們引出了工廠模式中的最後一種:抽象工廠
    抽象工廠解決的問題屬於創建一個產品族,舉個例子就是工廠裏生產蘋果電腦、蘋果手機、蘋果手環等等,生產出來的家族產品可以很吻合的配合使用。(這裏應該把抽象工廠定義成家族工廠是不是更合適些?嘿嘿嘿...)

    有了以上工廠模式的基礎,抽象工廠就很簡單了,現在工廠只生產電腦,那麼我們直接把手機產品線也放進去好了,得到的結果就是生產出來的要麼是ApplePC+iPhone,要麼是DellPC+DPhnoe(額。。自己開創品牌),擡椅子上馬:

//抽象產品(電腦)
class PC
{
public:
    virtual string getCPU() = 0;
};

//具體產品(Apple電腦)
class ApplePC : public PC
{
public:
    string getCPU()
    {
        return "AppleCPU";
    }
};

//具體產品(Dell電腦)
class DellPC : public PC
{
public:
    string getCPU()
    {
        return "DellCPU";
    }
};

//抽象產品(手機)
class Phone
{
public:
    virtual string call() = 0;
};

//具體產品(iPhone)
class iPhone : public Phone
{
public:
    string call()
    {
        return "iPhone du...du...";
    }
};

//具體產品(DPhone)
class DPhone : public Phone
{
public:
    string call()
    {
        return "DPhone du...du...";
    }
};

//抽象工廠(工廠總部)
class Factory
{
public:
    virtual PC* createPC() = 0;
    virtual Phone* createPhone() = 0;
};

//具體工廠(Apple工廠)
class AppleFactory : public Factory
{
public:
    PC* createPC()
    {
        return new ApplePC;
    }
    Phone* createPhone()
    {
        return new iPhone;
    }
};

//具體工廠(Dell工廠)
class DellFactory : public Factory
{
public:
    PC* createPC()
    {
        return new DellPC;
    }
    Phone* createPhone() 
    {
        return new DPhone;
    }
};

int main(int argc, char* argv[])
{
    Factory* f = new AppleFactory; //下達指令到Apple工廠(要生產Apple系列產品)
    PC* pPC = f->createPC();      //Apple工廠生產Apple mac
    Phone* pPhone = f->createPhone(); //Apple工廠生產iPhone

    cout << pPC->getCPU() << endl; //使用Apple Mac
    cout << pPhone->call() << endl;//使用iPhone

    return 0;
}

到此,工廠模式的三種類型都講完了。

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