工廠模式是個系列充甚,分為簡單工廠模式以政, 工廠方法模式, 抽象工廠模式伴找,這三種模式也非常常用盈蛮。這些模式最最經(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)购裙,請看下回分解懂版。?