工廠模式
三類:簡單工廠模式(Simple Factory),工廠方法模式(Factory Method),抽象工廠模式(Abstract Factory)
定義:簡單工廠模式又稱爲靜態工廠方法(Static Factory Method)模式,它屬於類創建型模式。在簡單工廠模式中,可以根據參數的不同返回不同類的實例。簡單工廠模式專門定義一個類來負責創建其他類的實例,被創建的實例通常都具有共同的父類。
實現:簡單工廠
具體情形:有一個肥皂廠,生產各種肥皂,有舒膚佳,夏士蓮,娜愛斯等。給這個肥皂廠建模。
UML圖如下:
對於簡單設計模式的結構圖,我們可以很清晰的看到它的組成:
1) 工廠類角色:這是本模式的核心,含有一定的商業邏輯和判斷邏輯。
2) 抽象產品角色:它一般是具體產品繼承的父類或者實現的接口。
3) 具體產品角色:工廠類所創建的對象就是此角色的實例。
簡單設計模式存在的目的很簡單:定義一個用於創建對象的接口。
缺點:
對修改不封閉,新增加產品您要修改工廠。違法了鼎鼎大名的開閉法則(OCP)。
由於工廠類集中了所有產品創建邏輯,一旦不能正常工作,整個系統都要受到影響。
使用簡單工廠模式將會增加系統中類的個數,在一定程序上增加了系統的複雜度和理解難度。
系統擴展困難,一旦添加新產品就不得不修改工廠邏輯,在產品類型較多時,有可能造成工廠邏輯過於複雜,不利於系統的擴展和維護。
簡單工廠模式由於使用了靜態工廠方法,造成工廠角色無法形成基於繼承的等級結構。
代碼實現:
1.#include <iostream>
2.using namespace std;
3.enum PRODUCTTYPE {SFJ,XSL,NAS};
4.class soapBase
5.{
6. public:
7. virtual ~soapBase(){};
8. virtual void show() = 0;
9.};
10.
11.class SFJSoap:public soapBase
12.{
13. public:
14. void show() {cout<<"SFJ Soap!"<<endl;}
15.};
16.
17.class XSLSoap:public soapBase
18.{
19. public:
20. void show() {cout<<"XSL Soap!"<<endl;}
21.};
22.
23.class NASSoap:public soapBase
24.{
25. public:
26. void show() {cout<<"NAS Soap!"<<endl;}
27.};
28.
29.class Factory
30.{
31. public:
32. soapBase * creatSoap(PRODUCTTYPE type)
33. {
34. switch(type)
35. {
36. case SFJ:
37. return new SFJSoap();
38. break;
39. case XSL:
40. return new XSLSoap();
41. break;
42. case NAS:
43. return new NASSoap();
44. break;
45. default:break;
46. }
47.
48. }
49.};
50.
51.int main()
52.{
53. Factory factory;
54. soapBase* pSoap1 = factory.creatSoap(SFJ);
55. pSoap1->show();
56. soapBase* pSoap2 = factory.creatSoap(XSL);
57. pSoap2->show();
58. soapBase* pSoap3 = factory.creatSoap(NAS);
59. pSoap3->show();
60. delete pSoap1;
61. delete pSoap2;
62. delete pSoap3;
63. return 0;
64.}
以下情況下可以使用簡單工廠模式:
工廠類負責創建的對象比較少:由於創建的對象較少,不會造成工廠方法中的業務邏輯太過複雜。
客戶端只知道傳入工廠類的參數,對於如何創建對象不關心:客戶端既不需要關心創建細節,甚至連類名都不需要記住,只需要知道類型所對應的參數。
工廠模式:
定義:用於創建對象的接口,讓子類決定實例化哪一個類。工廠方法使一個類的實例化延遲到其子類。
實現:
最近莫名肥皂需求激增!! 於是要獨立每個生產線,每個生產線只生產一種肥皂。
UML圖如下:
1)抽象工廠角色: 這是工廠方法模式的核心,它與應用程序無關。是具體工廠角色必須實現的接口或者必須繼承的父類。
2)具體工廠角色:它含有和具體業務邏輯有關的代碼。由應用程序調用以創建對應的具體產品的對象。
3)抽象產品角色:它是具體產品繼承的父類或者是實現的接口。
4)具體產品角色:具體工廠角色所創建的對象就是此角色的實例。
優點:
良好的封裝性,代碼結構清晰;降低模塊的耦合性;擴展優秀;典型的解耦框架,高層模塊只需要知道產品的抽象類。
缺點:
由於工廠類集中了所有產品創建邏輯,一旦不能正常工作,整個系統都要受到影響。
使用簡單工廠模式將會增加系統中類的個數,在一定程序上增加了系統的複雜度和理解難度。
系統擴展困難,一旦添加新產品就不得不修改工廠邏輯,在產品類型較多時,有可能造成工廠邏輯過於複雜,不利於系統的擴展和維護。
以下情況下可以使用工廠方法模式:
一個類不知道它所需要的對象的類:在工廠方法模式中,客戶端不需要知道具體產品類的類名,只需要知道所對應的工廠即可,具體的產品對象由具體工廠類創建;客戶端需要知道創建具體產品的工廠類。
一個類通過其子類來指定創建哪個對象:在工廠方法模式中,對於抽象工廠類只需要提供一個創建產品的接口,而由其子類來確定具體要創建的對象,利用面向對象的多態性和里氏代換原則,在程序運行時,子類對象將覆蓋父類對象,從而使得系統更容易擴展。
將創建對象的任務委託給多個工廠子類中的某一個,客戶端在使用時可以無須關心是哪一個工廠子類創建產品子類,需要時再動態指定,可將具體工廠類的類名存儲在配置文件或數據庫中。
代碼實現:
1.#include <iostream>
2.using namespace std;
3.enum SOAPTYPE {SFJ,XSL,NAS};
4.
5.class soapBase
6.{
7. public:
8. virtual ~soapBase(){};
9. virtual void show() = 0;
10.};
11.
12.class SFJSoap:public soapBase
13.{
14. public:
15. void show() {cout<<"SFJ Soap!"<<endl;}
16.};
17.
18.class XSLSoap:public soapBase
19.{
20. public:
21. void show() {cout<<"XSL Soap!"<<endl;}
22.};
23.
24.class NASSoap:public soapBase
25.{
26. public:
27. void show() {cout<<"NAS Soap!"<<endl;}
28.};
29.
30.class FactoryBase
31.{
32. public:
33. virtual soapBase * creatSoap() = 0;
34.};
35.
36.class SFJFactory:public FactoryBase
37.{
38. public:
39. soapBase * creatSoap()
40. {
41. return new SFJSoap();
42. }
43.};
44.
45.class XSLFactory:public FactoryBase
46.{
47. public:
48. soapBase * creatSoap()
49. {
50. return new XSLSoap();
51. }
52.};
53.
54.class NASFactory:public FactoryBase
55.{
56. public:
57. soapBase * creatSoap()
58. {
59. return new NASSoap();
60. }
61.};
62.
63.
64.
65.int main()
66.{
67. SFJFactory factory1;
68. soapBase* pSoap1 = factory1.creatSoap();
69. pSoap1->show();
70. XSLFactory factory2;
71. soapBase* pSoap2 = factory2.creatSoap();
72. pSoap2->show();
73. NASFactory factory3;
74. soapBase* pSoap3 = factory3.creatSoap();
75. pSoap3->show();
76. delete pSoap1;
77. delete pSoap2;
78. delete pSoap3;
79. return 0;
80.}
抽象工廠類:
定義:爲創建一組相關或相關依賴的對象提供給一個接口,而且無需指定他們的具體類;
實現:
對於上面的結構圖,可以看出抽象工廠模式,比前兩者更爲的複雜和一般性,抽象工廠模式和工廠方法模式的區別就在於需要創建對象的複雜程度上。
抽象工廠模式:給客戶端提供一個接口,可以創建多個產品族中的產品對象 ,而且使用抽象工廠模式還要滿足一下條件:
1)系統中有多個產品族,而系統一次只可能消費其中一族產品。
2)同屬於同一個產品族的產品以其使用。
抽象工廠模式的組成(和工廠方法模式一樣):
1)抽象工廠角色:這是工廠方法模式的核心,它與應用程序無關。是具體工廠角色必須實現的接口或者必須繼承的父類。
2)具體工廠角色:它含有和具體業務邏輯有關的代碼。由應用程序調用以創建對應的具體產品的對象。
3)抽象產品角色:它是具體產品繼承的父類或者是實現的接口。
4)具體產品角色:具體工廠角色所創建的對象就是此角色的實例。
優點:
封裝性,產品實現類只要知道工廠類是誰就能創建出一個需要的對象。
產品族內約束非公開。
缺點:產品族擴展難(產品族由2變到3)
使用場景: 跨平臺應用
一個對象族(或者沒有任何關係的對象)有相同的約束,則可以使用抽象工廠模式
一個系統不應當依賴於產品類實例如何被創建、組合和表達的細節,這對於所有類型的工廠模式都是重要的。
系統中有多於一個的產品族,而每次只使用其中某一產品族。
屬於同一個產品族的產品將在一起使用,這一約束必須在系統的設計中體現出來。
系統提供一個產品類的庫,所有的產品以同樣的接口出現,從而使客戶端不依賴於具體實現。
抽象工廠模式與工廠方法模式的區別
抽象工廠模式是工廠方法模式的升級版本,他用來創建一組相關或者相互依賴的對象。他與工廠方法模式的區別就在於,工廠方法模式針對的是一個產品等級結構;而抽象工廠模式則是針對的多個產品等級結構。在編程中,通常一個產品結構,表現爲一個接口或者抽象類,也就是說,工廠方法模式提供的所有產品都是衍生自同一個接口或抽象類,而抽象工廠模式所提供的產品則是衍生自不同的接口或抽象類。
在抽象工廠模式中,有一個產品族的概念:所謂的產品族,是指位於不同產品等級結構中功能相關聯的產品組成的家族。抽象工廠模式所提供的一系列產品就組成一個產品族;而工廠方法提供的一系列產品稱爲一個等級結構。我們依然拿生產汽車的例子來說明他們之間的區別。
在上面的類圖中,兩廂車和三廂車稱爲兩個不同的等級結構;而2.0排量車和2.4排量車則稱爲兩個不同的產品族。再具體一點,2.0排量兩廂車和2.4排量兩廂車屬於同一個等級結構,2.0排量三廂車和2.4排量三廂車屬於另一個等級結構;而2.0排量兩廂車和2.0排量三廂車屬於同一個產品族,2.4排量兩廂車和2.4排量三廂車屬於另一個產品族。
明白了等級結構和產品族的概念,就理解工廠方法模式和抽象工廠模式的區別了,如果工廠的產品全部屬於同一個等級結構,則屬於工廠方法模式;如果工廠的產品來自多個等級結構,則屬於抽象工廠模式。在本例中,如果一個工廠模式提供2.0排量兩廂車和2.4排量兩廂車,那麼他屬於工廠方法模式;如果一個工廠模式是提供2.4排量兩廂車和2.4排量三廂車兩個產品,那麼這個工廠模式就是抽象工廠模式,因爲他提供的產品是分屬兩個不同的等級結構。當然,如果一個工廠提供全部四種車型的產品,因爲產品分屬兩個等級結構,他當然也屬於抽象工廠模式了。
代碼實現
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Human
{
public :
virtual void getColor() = 0;
virtual void talk() = 0;
virtual void getSex() = 0;
};
class AbstraWhiteHuman : public Human
{
public :
void getColor()
{
cout<<"白色人種的皮膚顏色是白色的"<<endl;
}
void talk()
{
cout<<"說話單字節"<<endl;
}
};
class AbstraBlackHuman : public Human
{
public :
void getColor()
{
cout<<"黑色人種的皮膚顏色是黑色的"<<endl;
}
void talk()
{
cout<<"說話聽不懂"<<endl;
}
};
class AbstraYellowHuman : public Human
{
public :
void getColor()
{
cout<<"黃種人種的皮膚顏色是黃色的"<<endl;
}
void talk()
{
cout<<"說話雙字節"<<endl;
}
};
class FemaleYellowHuman : public AbstraYellowHuman
{
public:
void getSex()
{
cout<<"黃人女性"<<endl;
}
};
class MaleYellowHuman : public AbstraYellowHuman
{
public:
void getSex()
{
cout<<"黃人男性"<<endl;
}
};
class FemaleBlackHuman : public AbstraBlackHuman
{
public:
void getSex()
{
cout<<"黑人女性"<<endl;
}
};
class MaleBlackHuman : public AbstraBlackHuman
{
public:
void getSex()
{
cout<<"黑人男性"<<endl;
}
};
class FemaleWhiteHuman : public AbstraWhiteHuman
{
public:
void getSex()
{
cout<<"白人女性"<<endl;
}
};
class MaleWhiteHuman : public AbstraWhiteHuman
{
public:
void getSex()
{
cout<<"白人男性"<<endl;
}
};
#if 0
class HumanFactory
{
public:
virtual FemaleYellowHuman createYellowHuman() = 0;
virtual FemaleWhiteHuman createWhiteHuman() = 0;
virtual FemaleBlackHuman createBlackHuman() = 0;
};
#endif
class HumanFactory
{
public:
virtual Human* createYellowHuman() = 0;
virtual Human* createWhiteHuman() = 0;
virtual Human* createBlackHuman() = 0;
};
class FemaleFactory: public HumanFactory
{
public:
Human* createBlackHuman()//java書上是返回Human 但是抽象類不允許返回
{
return new FemaleBlackHuman();//創建臨時對象
}
Human* createWhiteHuman()
{
return new FemaleWhiteHuman();
}
Human* createYellowHuman()
{
return new FemaleYellowHuman();
}
};
class MaleFactory: public HumanFactory
{
public:
public:
Human* createBlackHuman()//java書上是返回Human 但是抽象類不允許返回
{
return new MaleBlackHuman();//創建臨時對象
}
Human* createWhiteHuman()
{
return new MaleWhiteHuman();
}
Human* createYellowHuman()
{
return new MaleYellowHuman();
}
};
int main()
{
MaleFactory male;
HumanFactory *MaleFactory = &male ;
FemaleFactory female;
HumanFactory *FemaleFactory = ♀
Human *MaleYellowHuman = MaleFactory->createYellowHuman();
Human *FemaleYellowHuman = FemaleFactory->createYellowHuman();
cout<<"生產第一個黃色女性"<<endl;
FemaleYellowHuman->getColor();
FemaleYellowHuman->talk();
FemaleYellowHuman->getSex();
cout<<"生產第一個黃色男性"<<endl;
MaleYellowHuman->getColor();
MaleYellowHuman->talk();
MaleYellowHuman->getSex();
return 0;
}