工廠模式是個(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)看下回分解。?