最常用的設(shè)計模式----工廠模式家族(簡單工廠模式逃顶, 工廠方法模式, 抽象工廠模式)

工廠模式是個系列充甚,分為簡單工廠模式以政, 工廠方法模式, 抽象工廠模式伴找,這三種模式也非常常用盈蛮。這些模式最最經(jīng)典的就例子就是設(shè)計計算器。

? ? ?簡單工廠模式

? ? ? ? ?嚴(yán)格的說技矮,簡單工廠模式并不是23種常用的設(shè)計模式之一抖誉,它只算工廠模式的一個特殊實現(xiàn)。簡單工廠模式在實際中的應(yīng)用相對于其他2個工廠模式用的還是相對少得多衰倦,因為它只適應(yīng)很多簡單的情況袒炉,最最重要的是它違背了我們在概述中說的開放-封閉原則。因為每次你要新添加一個功能樊零,都需要在生switch-case 語句(或者if-else 語句)中去修改代碼我磁,添加分支條件孽文。

簡單工廠模式角色分配:

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

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

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

? ? ? ? ? ? ? 簡單工廠模式所創(chuàng)建的所有對象的父類郁副,它負(fù)責(zé)描述所有實例所共有的公共接口减牺。

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

? ? ? ? ? ? ? 是簡單工廠模式的創(chuàng)建目標(biāo),所有創(chuàng)建的對象都是充當(dāng)這個角色的某個具體類的實例存谎。

簡單工廠模式uml圖:


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

class Phone

{

public:

virtual ~Phone(){};//在刪除的時候防止內(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;

}

};

客戶端這樣實現(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;

}

}

這就是簡單工廠方法墩虹,把所有的創(chuàng)建交給creator,creator 通過switch-case(或者if-else)語句來選擇具體創(chuàng)建的對象。簡單明了憨琳。但是就如上面所說诫钓,它最致命的問題的違背了開放-封閉原則。每次你要新添加一個功能篙螟,都要修改factor里面的createPhone代碼菌湃。 但是工廠方法模式可以解決這個問題。

? ?工廠方法模式

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

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

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

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

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

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

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

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



? ? ? 看定義看的暈乎乎的余掖?那么我們來看代碼:

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

class Phone

{

public:

virtual ~Phone(){};//在刪除的時候防止內(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;}

};

上面這個和簡單工廠方法還是一樣的盐欺。接下來不一樣的來了...

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不在像以前那樣將所有的判斷塞到里面仅醇。而是改由其子類來實現(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)建工作交給子類去完成。也就是后所這個核心工廠僅僅只是提供創(chuàng)建的接口叶摄,具體實現(xiàn)方法交給繼承它的子類去完成属韧。當(dāng)我們的系統(tǒng)需要增加其他新功能時,只需要繼承PhoneFactory這個類蛤吓,并且實現(xiàn)createPhone接口宵喂。 不需要對原工廠PhoneFactory進(jìn)行任何修改,這樣很好地符合了“開放-封閉“原則会傲。

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

抽象工廠模式

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



? ? ? ?產(chǎn)品等級結(jié)構(gòu):產(chǎn)品的等級結(jié)構(gòu)也就是產(chǎn)品的繼承結(jié)構(gòu)梭稚。我理解就是同一類產(chǎn)品颖低,比如手機是一個系列,有android手機弧烤,ios手機忱屑,win手機,那么這個抽象類手機和他的子類就構(gòu)成了一個產(chǎn)品等級結(jié)構(gòu)暇昂。那其他的平板顯然不是和手機一個系列的莺戒,一個平板,一個是手機急波,所以他們是不同的產(chǎn)品等級結(jié)構(gòu)从铲。

? ? ? ?產(chǎn)品族: 在抽象工廠模式中,產(chǎn)品族是指由同一個工廠生產(chǎn)的澄暮,位于不同產(chǎn)品等級結(jié)構(gòu)中的一組產(chǎn)品食店。比如分為android產(chǎn)品,和ios產(chǎn)品赏寇。其中一個ios產(chǎn)品包含ios手機和ios平板吉嫩。顯然ios手機和ios平板不是同一個產(chǎn)品等級結(jié)構(gòu)的,因為一個是手機嗅定,一個是平板自娩。但他們是同一個產(chǎn)品簇---都是ios產(chǎn)品。

? ? ? ?希望大家通過上面的例子大家明白了這兩個概念渠退。

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


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

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

class Phone

{

public:

virtual ~Phone(){};//在刪除的時候防止內(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)品等級結(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; }

};

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

class MobileFactory

{

public:

virtual ~MobileFactory(){};

virtual Phone* createPhone() = 0;

virtual Pad* createPad() = 0;

};

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

class AndroidFactory : public MobileFactory

{

public:

Phone* createPhone()

{

return new AndroidPhone();

}

Pad* createPad()

{

return new AndroidPad();

}

};

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

class IosFactory : public MobileFactory

{

public:

Phone* createPhone()

{

return new IosPhone();

}

Pad* createPad()

{

return new IosPad();

}

};

最后客戶端這樣實現(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();

//這里沒有做釋放和判斷梗掰,請自己判斷和釋放

}

總結(jié):

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

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

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

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市缓窜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌谍咆,老刑警劉巖禾锤,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異摹察,居然都是意外死亡恩掷,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門供嚎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來黄娘,“玉大人,你說我怎么就攤上這事克滴”普” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵劝赔,是天一觀的道長誓焦。 經(jīng)常有香客問我,道長着帽,這世上最難降的妖魔是什么杂伟? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮仍翰,結(jié)果婚禮上赫粥,老公的妹妹穿的比我還像新娘。我一直安慰自己予借,他們只是感情好越平,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著灵迫,像睡著了一般喧笔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上龟再,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天书闸,我揣著相機與錄音,去河邊找鬼利凑。 笑死浆劲,一個胖子當(dāng)著我的面吹牛嫌术,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播牌借,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼度气,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了膨报?” 一聲冷哼從身側(cè)響起磷籍,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎现柠,沒想到半個月后院领,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡够吩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年比然,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片周循。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡强法,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出湾笛,到底是詐尸還是另有隱情饮怯,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布嚎研,位于F島的核電站硕淑,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏嘉赎。R本人自食惡果不足惜置媳,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望公条。 院中可真熱鬧拇囊,春花似錦、人聲如沸靶橱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽关霸。三九已至传黄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間队寇,已是汗流浹背膘掰。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人识埋。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓凡伊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親窒舟。 傳聞我的和親對象是個殘疾皇子系忙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容