最常用的設(shè)計(jì)模式----工廠模式家族(簡(jiǎn)單工廠模式, 工廠方法模式, 抽象工廠模式)

工廠模式是個(gè)系列,分為簡(jiǎn)單工廠模式, 工廠方法模式, 抽象工廠模式,這三種模式也非常常用。這些模式最最經(jīng)典的就例子就是設(shè)計(jì)計(jì)算器。

? ? ?簡(jiǎn)單工廠模式

? ? ? ? ?嚴(yán)格的說(shuō),簡(jiǎn)單工廠模式并不是23種常用的設(shè)計(jì)模式之一,它只算工廠模式的一個(gè)特殊實(shí)現(xiàn)。簡(jiǎn)單工廠模式在實(shí)際中的應(yīng)用相對(duì)于其他2個(gè)工廠模式用的還是相對(duì)少得多,因?yàn)樗贿m應(yīng)很多簡(jiǎn)單的情況,最最重要的是它違背了我們?cè)诟攀鲋姓f(shuō)的開放-封閉原則。因?yàn)槊看文阋绿砑右粋€(gè)功能,都需要在生switch-case 語(yǔ)句(或者if-else 語(yǔ)句)中去修改代碼,添加分支條件。

簡(jiǎn)單工廠模式角色分配:

? ? ? ?Creator(產(chǎn)品創(chuàng)建者)

? ? ? ? ? ? ? 簡(jiǎn)單工廠模式的核心,它負(fù)責(zé)實(shí)現(xiàn)創(chuàng)建所有實(shí)例的內(nèi)部邏輯。工廠類可以被外界直接調(diào)用,創(chuàng)建所需的產(chǎn)品對(duì)象。

? ? ? Product ( 產(chǎn)品抽象類)

? ? ? ? ? ? ? 簡(jiǎn)單工廠模式所創(chuàng)建的所有對(duì)象的父類,它負(fù)責(zé)描述所有實(shí)例所共有的公共接口。

? ? ? ?Concrete Product (具體產(chǎn)品)

? ? ? ? ? ? ? 是簡(jiǎn)單工廠模式的創(chuàng)建目標(biāo),所有創(chuàng)建的對(duì)象都是充當(dāng)這個(gè)角色的某個(gè)具體類的實(shí)例。

簡(jiǎn)單工廠模式uml圖:


? ? ? 考慮下面一個(gè)事例: 加入你是一個(gè)商人,你做的的是手機(jī)生意?,F(xiàn)在你生產(chǎn)android 手機(jī)和iphone等,考慮到以后你可能還會(huì)生產(chǎn)其他手機(jī)例如ubuntu手機(jī)。假定你選擇了簡(jiǎn)單工廠模式來(lái)實(shí)現(xiàn)。那么顯然,我們需要所有產(chǎn)品的抽象基類(Product) 即是Phone類:

class Phone

{

public:

virtual ~Phone(){};//在刪除的時(shí)候防止內(nèi)存泄露

virtual void call(string number) = 0;

};

然后我們需要具體的產(chǎn)品類 Concrete Product:?AndroidPhone 和 IosPhone

class AndroidPhone : public Phone

{

public:

void call(string number){ cout<<"AndroidPhone is calling..."<<endl;}

};

class IosPhone : public Phone

{

public:

void call(string number) { cout<<"IosPhone is calling..."<<endl;}

};

最后我們需要Creator

class PhoneFactory

{

public:

Phone* createPhone(string phoneName)

{

if(phoneName == "AndroidPhone")

{

return new AndroidPhone();

}else if(phoneName == "IosPhone")

{

return new IosPhone();

}

return NULL;

}

};

客戶端這樣實(shí)現(xiàn):

void main()

{

PhoneFactor factory;

Phone* myAndroid = factory.createPhone("AndroidPhone");

Phone* myIPhone = factory.createPhone("IosPhone");

if(myAndroid)

{

myAndroid->call("123");

delete myAndroid;

myAndroid = NULL;

}

if(myIPhone)

{

myIPhone->call("123");

delete? myIPhone;

myIPhone = NULL;

}

}

這就是簡(jiǎn)單工廠方法,把所有的創(chuàng)建交給creator,creator 通過(guò)switch-case(或者if-else)語(yǔ)句來(lái)選擇具體創(chuàng)建的對(duì)象。簡(jiǎn)單明了。但是就如上面所說(shuō),它最致命的問(wèn)題的違背了開放-封閉原則。每次你要新添加一個(gè)功能,都要修改factor里面的createPhone代碼。 但是工廠方法模式可以解決這個(gè)問(wèn)題。

? ?工廠方法模式

? ? ? 個(gè)人覺得工廠方法模式在工廠模式家族中是用的最多模式。上面說(shuō)過(guò)了,如果簡(jiǎn)單工廠模式,要添加一個(gè)新功能,比如我現(xiàn)在要增加WinPhone 的生產(chǎn),那么我要修改PhoneFactory中的createPhone 中的分支判斷條件。這違背了開放-封閉原則,那為什么不能將創(chuàng)建方法放到子類中呢?

? ? ? 工廠方法的定義 就是:?定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類決定實(shí)例化哪一個(gè)類,工廠方法使一個(gè)類的實(shí)例化延遲到其子類。

? ? ? 工廠方法模式角色:

? ? ? ? ? ?抽象工廠(Creator)角色:是工廠方法模式的核心,與應(yīng)用程序無(wú)關(guān)。任何在模式中創(chuàng)建的對(duì)象的工廠類必須實(shí)現(xiàn)這個(gè)接口。

? ? ? ? ? ?具體工廠(Concrete Creator)角色:這是實(shí)現(xiàn)抽象工廠接口的具體工廠類,包含與應(yīng)用程序密切相關(guān)的邏輯,并且受到應(yīng)用程序調(diào)用以創(chuàng)建產(chǎn)品對(duì)象。

? ? ? ? ? ?抽象產(chǎn)品(Product)角色:工廠方法模式所創(chuàng)建的對(duì)象的超類型,也就是產(chǎn)品對(duì)象的共同父類或共同擁有的接口。

? ? ? ? ? ?具體產(chǎn)品(Concrete Product)角色:這個(gè)角色實(shí)現(xiàn)了抽象產(chǎn)品角色所定義的接口。某具體產(chǎn)品有專門的具體工廠創(chuàng)建,它們之間往往一一對(duì)應(yīng)。

? ? ? ?工廠方法模式uml圖:



? ? ? 看定義看的暈乎乎的?那么我們來(lái)看代碼:

? ? ? ?產(chǎn)品接口,以及其相應(yīng)的子類。

class Phone

{

public:

virtual ~Phone(){};//在刪除的時(shí)候防止內(nèi)存泄露

virtual void call(string number) = 0;

};

class AndroidPhone : public Phone

{

public:

void call(string number){ cout<<"AndroidPhone is calling..."<<endl;}

};

class IosPhone : public Phone

{

public:

void call(string number) { cout<<"IosPhone is calling..."<<endl;}

};

上面這個(gè)和簡(jiǎn)單工廠方法還是一樣的。接下來(lái)不一樣的來(lái)了...

class PhoneFactory

{

public:

virtual ~PhoneFactory(){};

virtual Phone* createPhone() = 0;

};

class AndroidPhoneFactory : public PhoneFactory

{

public:

virtual Phone* createPhone()

{

return new AndroidPhone();

}

};

class IosPhoneFactory : public PhoneFactory

{

public:

virtual Phone* createPhone()

{

return new IosPhone();

}

};

? ? ? ? 工廠方法將PhoneFactory抽象成了基類,PhoneFactory的createPhone不在像以前那樣將所有的判斷塞到里面。而是改由其子類來(lái)實(shí)現(xiàn)創(chuàng)建功能,這感覺就是權(quán)力下放。

客戶端:

void main()

{

PhoneFactory*? androidCreator = new AndroidPhoneFactory();

PhoneFactory*? iosCreator = new IosPhoneFactory();

Phone* myAndroid = androidCreator->createPhone();

Phone* myIPhone = iosCreator->createPhone();

if(myAndroid)

{

myAndroid->call("123");

delete myAndroid;

myAndroid = NULL;

}

if(myIPhone)

{

myIPhone->call("123");

delete? myIPhone;

myIPhone = NULL;

}

delete androidCreator;

delete iosCreator;

}

? ? ? ? 在工廠方法模式中,核心工廠類不在負(fù)責(zé)產(chǎn)品的創(chuàng)建,而是將具體的創(chuàng)建工作交給子類去完成。也就是后所這個(gè)核心工廠僅僅只是提供創(chuàng)建的接口,具體實(shí)現(xiàn)方法交給繼承它的子類去完成。當(dāng)我們的系統(tǒng)需要增加其他新功能時(shí),只需要繼承PhoneFactory這個(gè)類,并且實(shí)現(xiàn)createPhone接口。 不需要對(duì)原工廠PhoneFactory進(jìn)行任何修改,這樣很好地符合了“開放-封閉“原則。

? ? ? 雖然工廠方法模式滿足了"開放-封閉”原則,但是這個(gè)模式也仍然有缺點(diǎn):每次增加一個(gè)產(chǎn)品時(shí),都需要增加一個(gè)具體類和對(duì)象實(shí)現(xiàn)工廠,是的系統(tǒng)中類的個(gè)數(shù)成倍增加,在一定程度上增加了系統(tǒng)的復(fù)雜度,同時(shí)也增加了系統(tǒng)具體類的依賴。這并不是什么好事。

抽象工廠模式

? ? ?在工廠方法模式中,其實(shí)我們有一個(gè)潛在意識(shí)的意識(shí)。那就是我們生產(chǎn)的都是同一類產(chǎn)品,例如我們生產(chǎn)的都是手機(jī)!那么現(xiàn)在假如現(xiàn)在我們又要生產(chǎn)平板了了呢?那么就要用到抽象工廠模式。我抽象工廠模式也用的比較多在工廠模式家族中,僅次于工廠方法模式。在了解抽象工廠模式之前,還是老生常談的理清下產(chǎn)品等級(jí)結(jié)構(gòu)和產(chǎn)品簇的概念。下面的圖還是老圖。但是我講講我的理解:



? ? ? ?產(chǎn)品等級(jí)結(jié)構(gòu):產(chǎn)品的等級(jí)結(jié)構(gòu)也就是產(chǎn)品的繼承結(jié)構(gòu)。我理解就是同一類產(chǎn)品,比如手機(jī)是一個(gè)系列,有android手機(jī),ios手機(jī),win手機(jī),那么這個(gè)抽象類手機(jī)和他的子類就構(gòu)成了一個(gè)產(chǎn)品等級(jí)結(jié)構(gòu)。那其他的平板顯然不是和手機(jī)一個(gè)系列的,一個(gè)平板,一個(gè)是手機(jī),所以他們是不同的產(chǎn)品等級(jí)結(jié)構(gòu)。

? ? ? ?產(chǎn)品族: 在抽象工廠模式中,產(chǎn)品族是指由同一個(gè)工廠生產(chǎn)的,位于不同產(chǎn)品等級(jí)結(jié)構(gòu)中的一組產(chǎn)品。比如分為android產(chǎn)品,和ios產(chǎn)品。其中一個(gè)ios產(chǎn)品包含ios手機(jī)和ios平板。顯然ios手機(jī)和ios平板不是同一個(gè)產(chǎn)品等級(jí)結(jié)構(gòu)的,因?yàn)橐粋€(gè)是手機(jī),一個(gè)是平板。但他們是同一個(gè)產(chǎn)品簇---都是ios產(chǎn)品。

? ? ? ?希望大家通過(guò)上面的例子大家明白了這兩個(gè)概念。

? ? ? ?抽象工廠模式的Uml 圖:


? ? ?接著上面的話題,現(xiàn)在假如我要增加對(duì)平板的支持,那么我們肯定先添加兩個(gè)產(chǎn)品等級(jí)結(jié)構(gòu),一個(gè)是手機(jī),一個(gè)是平板:

//產(chǎn)品等級(jí)結(jié)構(gòu)--手機(jī)

class Phone

{

public:

virtual ~Phone(){};//在刪除的時(shí)候防止內(nèi)存泄露

virtual void call(string number) = 0;

};

class AndroidPhone : public Phone

{

public:

void call(string number){ cout<<"AndroidPhone is calling..."<<endl; }

};

class IosPhone : public Phone

{

public:

void call(string number) { cout<<"IosPhone is calling..."<<endl; }

};

//產(chǎn)品等級(jí)結(jié)構(gòu)--平板

class Pad

{

public:

virtual ~Pad(){};

virtual void playMovie() = 0;

};

class AndroidPad : public Pad

{

public:

virtual void playMovie(){ cout<<"AndriodPad is playing movie..."<<endl; }

};

class IosPad : public Pad

{

public:

virtual void playMovie(){ cout<<"IosPad is playing movie..."<<endl; }

};

然后具體的工廠我們整個(gè)工廠是生產(chǎn)移動(dòng)設(shè)備的所以我們?nèi)∶麨镸obileFactory,然后工廠可以生產(chǎn)平板和手機(jī),故有了createPhone 和createPad兩個(gè)接口。

class MobileFactory

{

public:

virtual ~MobileFactory(){};

virtual Phone* createPhone() = 0;

virtual Pad* createPad() = 0;

};

接著是 android 產(chǎn)品簇 的工廠類,負(fù)責(zé)生產(chǎn)android 的手機(jī)和平板:

class AndroidFactory : public MobileFactory

{

public:

Phone* createPhone()

{

return new AndroidPhone();

}

Pad* createPad()

{

return new AndroidPad();

}

};

接著是ios的產(chǎn)品簇的工廠類,負(fù)責(zé)生產(chǎn)ios的手機(jī)和平板:

class IosFactory : public MobileFactory

{

public:

Phone* createPhone()

{

return new IosPhone();

}

Pad* createPad()

{

return new IosPad();

}

};

最后客戶端這樣實(shí)現(xiàn):

void main()

{

MobileFactory*? androidCreator = new AndroidFactory();

MobileFactory*? iosCreator = new IosFactory();

Phone* myAndroidPhone = androidCreator->createPhone();

Pad* myAndroidPad = androidCreator->createPad();

Phone* myIosPhone = iosCreator->createPhone();

Pad* myIosPad = iosCreator->createPad();

myAndroidPhone->call("123");

myAndroidPad->playMovie();

myIosPhone->call("123");

myIosPad->playMovie();

//這里沒有做釋放和判斷,請(qǐng)自己判斷和釋放

}

總結(jié):

? ? 抽象工廠模式適用于那些有多種產(chǎn)品的產(chǎn)品簇,并且每次使用其中的某一產(chǎn)品簇的產(chǎn)品。

? ? 缺點(diǎn) : 抽象工廠模式的添加新功能也非常麻煩,比工廠方法模式都還要復(fù)雜的多。

? ? 優(yōu)點(diǎn):?當(dāng)一個(gè)產(chǎn)品族中的多個(gè)對(duì)象被設(shè)計(jì)成一起工作時(shí),它能夠保證客戶端始終只使用同一個(gè)產(chǎn)品族中的對(duì)象。

上面說(shuō)到抽象工廠和工廠方法模式的功能添加都非常復(fù)雜,那么我們有沒有什么辦法可以簡(jiǎn)化呢? 答案是肯定有的: 那就是工廠模式 + ?配置文件 + 反射。具體怎么實(shí)現(xiàn),請(qǐng)看下回分解。?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容