工厂模式

  工厂模式是23种常用设计模式里比较重要的模式。这个设计模式解决的是“制造对象”的问题。在面向对象中,对于复杂数据类型,需要通过类的实例化来“new”新的对象。问题是,实例化的具体对象在很多情况下不是一层不变的,程序需要通过具体的运行条件判断到底实例化哪个类。例如下面是一个模拟给家具上漆的程序:

 

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<map>
 4 #include<string>
 5 using namespace std;
 6 
 7 
 8 //先看一个最简单的代码,不使用任何的实际模式
 9 //场景是这样的,有一个油漆加工的程序,要对刚刚做好的家具进行上色。家具类中包含一个上色的方法(setColor)
10 enum FUR{chair,table,bed,bookcase,sofa};
11 enum COLOUR{RED,YELLOW,BLUE,GREEN,BLACK,WHITE,PURPLE};
12 map<COLOUR, string>m;
13 
14 //首先我们需要一个家具类作为基类
15 class furniture{
16 
17 public:
18     furniture(){}
19     ~furniture(){}
20     void setColor(COLOUR C ){
21         this->colour = C;
22     }
23     void setPrice(double p){
24         this->price = p;
25     }
26     void showColour(){
27         cout << "Color: "<< m[this->colour]<< endl;
28     }
29 
30 private:
31     double price;
32     COLOUR colour;
33 
34 };
35 //然后写派生类
36 class Table :public furniture{
37 public:
38     Table(){ this->setPrice(10.0); }
39     ~Table(){}
40 };
41 class Bed :public furniture{
42 public:
43     Bed(){ this->setPrice(200.0); }
44     ~Bed(){}
45 };
46 class Bookcase :public furniture{
47 public:
48     Bookcase(){ this->setPrice(150.0); }
49     ~Bookcase(){}
50 };
51 class Sofa :public furniture{
52 public:
53     Sofa(){ this->setPrice(50.0); }
54     ~Sofa(){}
55 };
56 class Chair :public furniture{
57 public:
58     Chair(){ this->setPrice(50.0); }
59     ~Chair(){}
60 };
61 void init(){
62     m.insert(make_pair(RED, "RED"));
63     m.insert(make_pair(YELLOW, "YELLOW"));
64     m.insert(make_pair(BLUE, "BLUE"));
65     m.insert(make_pair(WHITE, "WHITE"));
66     m.insert(make_pair(BLACK, "BLACK"));
67     m.insert(make_pair(PURPLE, "PURPLE"));
68     m.insert(make_pair(GREEN, "GREEN"));
69 }
70 //有一个油漆加工的程序,
71 furniture*Paint(COLOUR C,FUR F){
72     furniture*f;
73     switch (F){
74     case chair:  f = new Chair(); break;
75     case table:  f = new Table(); break;
76     case bed:     f = new Bed(); break;
77     case sofa:     f = new Sofa(); break;
78     default:     f = new Bookcase(); break;
79     }
80     f->setColor(C);
81     return f;
82 }
83 int main(){
84     init();
85     COLOUR C = YELLOW;
86     FUR F = bookcase;
87     furniture*f = Paint(C, F);
88     f->showColour();
89     system("pause");
90     return 0;
91 }

 

 

 

  Paint函数到底实例化哪种家具是运行过程中决定的。这种实例化对象的方法无疑会带问题,首先,这种实例化的方式违反了OO原则中“对修改关闭,对扩展开发”的原则。如果有新的子类出现,则需要修改selectType函数中的相应代码也要修改。其次,这里只举了一个上漆的例子,如果有相似的类,如打光,雕刻等,每个类都需要用到这一套实例化类的逻辑,就会造成大量的代码冗余。所以这种“制造对象”的方法还有很大的改进空间。

  仔细分析这个问题,可以发现,我们可以把涉及到实例化对象的代码分成两部分,一部分是实例化对象的过程,它会根据运行条件创造一个具体的对象,还有一部分代码是和具体对象无关的,是所有类通用的接口,对象的具体类别不影响这部分代码的逻辑。如果是这样,那我们就可以将那部分实例化的代码从原来的类中提取出来,封装成一个专门用来实例化对象的类或者方法。

  被封装的这部分代码被称为工厂。在社会生活中,工厂是用来生产某类产品的,例如糖果工厂会生产糖果,陶瓷工厂会生产陶瓷。现在,我们通过工厂模式生成具体的对象,这些对象就是相当于工厂的产品。大型的工厂往往会生产多种品牌的产品,这些产品功能相同,但是风格,质量有差异的产品。这些差异不会影响我们对它的使用,例如,无论生产什么样的拖把,海绵的还是棉布的,我们都是拿它来拖地,无论生产什么样的水杯,我们都是拿它来喝水。工厂模式在软件开发中就起了类似的作用。只要这些“产品”有统一的接口,就不需要再关注具体的类,这样,使用该类的代码和实现该类的代码分离来,大大降低系统的耦合性。

  工厂模式包含三种,简单工厂模式,工厂模式,抽象工厂模式,下面就来一一介绍。

简单工厂模式

  先从最简单的简单工厂模式说起。简单工厂只有一个用来实例化对象的类或函数。相当于一个工厂,就能生产所有的产品,这个工厂可以说是一个超级工厂。

 

  简单工厂模式的实现符合我们对工厂的直观解读,它基本上就做了一件事,把所有和类的实例化相关的代码提取出来,然后封装到一个类里面去。这个类里面有一个接口函数,用来返回实例化的类。

 

 1 class simpleFactory{
 2 public:
 3     furniture*createFurniture(FUR F){
 4         furniture*f;
 5         switch (F){
 6             case chair:  f = new Chair(); break;
 7             case table:  f = new Table(); break;
 8             case bed:     f = new Bed(); break;
 9             case sofa:     f = new Sofa(); break;
10             default:     f = new Bookcase(); break;
11 
12         }
13         return f;
14     }
15 };
16 
17 furniture*Paint(COLOUR C, FUR F){
18     furniture*f;
19     simpleFactory s;
20     f = s.createFurniture(F);
21     f->setColor(C);
22     return f;
23

  虽然简单工厂将变化的那部分代码提取出来,并且进行了封装。但是它仍然违反了对修改关闭的原则,如果要生产新的产品,开发者还是得修改简单工厂这个类;另外,生产不同产品的流程不可能完全一样,如果把所有的流程都写入简单工厂,则这个类会变的非常臃肿。所以简单工厂模式一般用在产品的种类稳定,扩展比较少,且分类明确的情况下。

工厂模式

  在简单工厂模式中,所有产品都通过工厂生产,当产品数量增多时,会造成工厂类非常庞大。

  

 

 

 

 

  针对这个问题,很容易想到的一个解决方法就是对产品进行分类,然后再把超级工厂拆分成多个工厂,每一个工厂专门从事一类产品的生产。不同的工厂被称为产品等级。根据这一思想,我们可以首先定义一个抽象工厂(和后面抽象工厂模式中的抽象工厂不同),这个抽象工厂包含了一个工厂的最基础操作。然后,由这个工厂派生出多个具体工厂,具体工厂生产产品的实现方法存在差异。这样,既保证了生产产品的流程大致相同,又给了子类工厂一定的决定权,可以生产不同风格的产品。

 

下面是一个关于工厂模式的模拟程序:

  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<map>
  4 #include<string>
  5 using namespace std;
  6 
  7 
  8 //然后我们再看一个工厂模式的场景
  9 //工厂模式中有三个客体,产品,调用者(使用产品的人),工厂(生产产品)
 10 //首先先看产品,产品有一个共有的基类
 11 
 12 class Product{
 13 public:
 14     virtual void introduce() = 0;
 15     void showprice(){
 16         cout << " It cost: " << this->price;
 17     }
 18     void setName(string _type){
 19         this->type = _type;
 20     }
 21     void setPrice(double _price){
 22         this->price = _price;
 23     }
 24     double getPrict(){
 25         return this->price;
 26     }
 27 private:
 28     string type;
 29     double price;
 30 };
 31 
 32 //假设有四类产品,每个厂家都可以生产
 33 enum productType{ Type1 = 0, Type2, Type3, Type4 };
 34 class ProductType1 :public Product{
 35 public:
 36     ProductType1(){
 37         this->setName("Type1");
 38         this->setPrice(10.0);
 39     }
 40     void introduce(){
 41         cout << "This is ProductType1.";
 42         this->showprice();
 43         cout<<" It could..." << endl;
 44     }
 45 };
 46 class ProductType2 :public Product{
 47 public:
 48     ProductType2(){
 49         this->setName("Type2");
 50         this->setPrice(20.0);
 51     }
 52     void introduce(){
 53         cout << "This is ProductType2.";
 54         this->showprice();
 55         cout << " It could..." << endl;
 56     }
 57 };
 58 class ProductType3 :public Product{
 59 public:
 60     ProductType3(){
 61         this->setName("Type3");
 62         this->setPrice(30.0);
 63     }
 64     void introduce(){
 65         cout << "This is ProductType3.";
 66         this->showprice();
 67         cout << " It could..." << endl;
 68     }
 69 };
 70 class ProductType4 :public Product{
 71 public:
 72     ProductType4(){
 73         this->setName("Type4");
 74         this->setPrice(40.0);
 75     }
 76     void introduce(){
 77         cout << "This is ProductType4.";
 78         this->showprice();
 79         cout << " It could..." << endl;
 80     }
 81 };
 82 
 83 //然后是工厂,每个工厂必须有一个实例化对象的接口
 84 class simpleFactory{
 85 
 86 public:
 87     virtual Product*createProduct(productType p) = 0;
 88 
 89 };
 90 // 现假设有不同的工厂A,B,每个工厂加工出的产品不一样,在这个基础上,又可以派生出更多的子类
 91 class ProductType1A :public ProductType1{
 92 public:
 93     void introduce(){
 94         cout << "This is ProductType1.";
 95         this->showprice();
 96         cout << " The Product coms from factory A.";
 97         cout << " It could..." << endl;
 98         
 99     }
100 };
101 class ProductType1B :public ProductType1{
102 public:
103     void introduce(){
104         cout << "This is ProductType1.";
105         this->showprice();
106         cout << " The Product coms from factory B.";
107         cout << " It could..." << endl;
108     }
109 };
110 class ProductType2A :public ProductType2{
111 public:
112     void introduce(){
113         cout << "This is ProductType2.";
114         this->showprice();
115         cout << " The Product coms from factory A.";
116         cout << " It could..." << endl;
117     }
118 };
119 class ProductType2B :public ProductType2{
120 public:
121     void introduce(){
122         cout << "This is ProductType2.";
123         this->showprice();
124         cout << " The Product coms from factory B.";
125         cout << " It could..." << endl;
126     }
127 };
128 
129 class ProductType3A :public ProductType3{
130 public:
131     void introduce(){
132         cout << "This is ProductType3.";
133         this->showprice();
134         cout << " The Product coms from factory A.";
135         cout << " It could..." << endl;
136     }
137 };
138 class ProductType3B :public ProductType3{
139 public:
140     void introduce(){
141         cout << "This is ProductType3.";
142         this->showprice();
143         cout << " The Product coms from factory B.";
144         cout << " It could..." << endl;
145     }
146 };
147 class ProductType4A :public ProductType4{
148 public:
149     void introduce(){
150         cout << "This is ProductType4.";
151         this->showprice();
152         cout << " The Product coms from factory A.";
153         cout << " It could..." << endl;
154     }
155 };
156 class ProductType4B :public ProductType4{
157 public:
158     void introduce(){
159         cout << "This is ProductType4.";
160         this->showprice();
161         cout << " The Product coms from factory B.";
162         cout << " It could..." << endl;
163     }
164 };
165 
166 class AFactory :public simpleFactory{
167 
168 public:
169     Product*createProduct(productType p){
170         Product*P;
171         switch (p){
172         case Type1: P = new ProductType1A(); break;
173         case Type2: P = new ProductType2A(); break;
174         case Type3: P = new ProductType3A(); break;
175         default:P = new ProductType4A(); break;
176         }
177         return P;
178     }
179 };
180 class BFactory :public simpleFactory{
181 
182 public:
183     Product*createProduct(productType p){
184         Product*P;
185         switch (p){
186         case Type1: P = new ProductType1B(); break;
187         case Type2: P = new ProductType2B(); break;
188         case Type3: P = new ProductType3B(); break;
189         default:P = new ProductType4B(); break;
190         }
191         return P;
192     }
193 };
194 
195 //最后是调用者
196 void getIntroduce(){
197     Product*P;
198     AFactory A;
199     BFactory B;
200     cout << "This is the Product Introduction Summary " << endl;
201     P = A.createProduct(Type1);
202     P->introduce();
203     delete P;
204     P = A.createProduct(Type2);
205     P->introduce();
206     delete P;
207     P = A.createProduct(Type3);
208     P->introduce();
209     delete P;
210     P = A.createProduct(Type4);
211     P->introduce();
212     delete P;
213     P = B.createProduct(Type1);
214     P->introduce();
215     delete P;
216     P = B.createProduct(Type2);
217     P->introduce();
218     delete P;
219     P = B.createProduct(Type3);
220     P->introduce();
221     delete P;
222     P = B.createProduct(Type4);
223     P->introduce();
224     delete P;
225     return;
226 }
227 
228 int main(){
229 
230     getIntroduce();
231     system("pause");
232     return 0;
233 }

  使用工厂模式的好处主要由两点。第一,如果要创建新的风格的产品,不需要修改原来的工厂类,创建一个新的工厂类就可以了。这样就符合了OO设计中,对修改关闭,对扩展开放的原则。第二,所有工厂的共性保留在抽象工厂中,这部分是不会变化的,生产产品的差异由具体工厂(子类)实现。变化和不变的部分再次分离了,进一步降低了系统的耦合性。

抽象工厂模式

  工厂模式解决了简单工厂模式职责过重的问题,但随之会造成产品类和工厂类的数量爆炸问题。抽象工厂模式就是为了改进工厂模式的这一缺点而创造的。抽象工厂模式引入了产品等级和产品族的概念。在抽象工厂模式中,一个工厂不在生产单一的产品,而是生产一系列相关的产品,这些相关的产品就是产品族。而产品等级是不同工厂生产的产品的标记,每个工厂生产的产品具有相同的产品等级。

  

   在抽象工厂模式中,我们不会再为每个产品等级的产品设置单独的类,而是设置一个抽象工厂,代表一个产品等级。工厂中包含了关于产品等级的抽象信息,这些信息可以让我们不用借助具体的类,也能创建产品族。

  下面,我们把上面工厂模式的这段代码改成抽象工厂模式。在工厂模式中,对每一个产品,我们需要考虑它的产品等级和产品族两个维度的信息,这就造成了我们的代码需要继承两次。在抽象工厂模式中,我们采用组合替换继承,以避免类数量的爆炸。首先,我们将TYPE1~TYPE4的产品视为一个产品族。然后,根据不同的产品等级设置抽象工厂。我们让具体的产品中携带了抽象工厂的相关信息,把抽象工厂和产品族两两组合,就可以得到不同的产品族。详细的代码如下所示:

  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<map>
  4 #include<string>
  5 using namespace std;
  6 
  7 
  8 enum productType{ TYPE1, TYPE2, TYPE3, TYPE4 };
  9 //对于抽象工厂模式,我们需要再设置一个信息类(价格,区域),通过信息来区分产品
 10 class factoryInformation{
 11 public:
 12     void setPrice(double price){
 13         this->basePrice = price;
 14     }
 15     void setRegion(string region){
 16         this->region = region;
 17     }
 18     double getPrice(){
 19         return this->basePrice;
 20     }
 21     string getRegion(){
 22         return this->region;
 23     }
 24     void showPriceandRegion(){
 25         cout << "Price:" << this->getPrice()<<endl;
 26         cout << "Region:" << this->getRegion() << endl;
 27     }
 28     virtual void informationShow() = 0;
 29 private:
 30     double basePrice;
 31     string region;
 32     
 33 };
 34 //关于A,B两个工厂的产品信息,在子类当中实现
 35 //两个工厂出产的产品在某些方面的应用不一样,例如在显示介绍的时候有区别
 36 class Afactoryinformation :public factoryInformation{
 37 public:
 38     void informationShow(){
 39 
 40         cout << "This is the information from factory A " << endl;
 41         cout << "A factory is a factory from ..." << endl;
 42         this->showPriceandRegion();
 43     }
 44 
 45 };
 46 class Bfactoryinformation : public factoryInformation{
 47 public:
 48     void informationShow(){
 49         cout << "Information about factory B  " << endl;
 50         cout << "Let's take a look about factory B..." << endl;
 51         this->showPriceandRegion();
 52     }
 53 };
 54 //产品的实现和information紧密相关
 55 class Product{
 56 public:
 57     Product(factoryInformation*_I) :I(_I){}
 58     virtual void introduce() = 0;
 59     factoryInformation*I;
 60 };
 61 class ProductType1 :public Product{
 62 public:
 63     ProductType1(factoryInformation*_I):Product(_I){}
 64     void introduce(){
 65         cout << "This is product 1" << endl;
 66         I->informationShow();
 67     }
 68 };
 69 class ProductType2 :public Product{
 70 public:
 71     ProductType2(factoryInformation*_I):Product(_I){}
 72     void introduce(){
 73         cout << "This is product 2" << endl;
 74         I->informationShow();
 75     }
 76 
 77 };
 78 class ProductType3 :public Product{
 79 public:
 80     ProductType3(factoryInformation*_I):Product(_I){}
 81     void introduce(){
 82         cout << "This is product 3" << endl;
 83         I->informationShow();
 84     }
 85 
 86 };
 87 class ProductType4 :public Product{
 88 public:
 89     ProductType4(factoryInformation*_I) :Product(_I){}
 90     void introduce(){
 91         cout << "This is product 4" << endl;
 92         I->informationShow();
 93     }
 94 };
 95 //最后是工厂类
 96 class simpleFactory{
 97 public:
 98     virtual Product*createProduct(productType p, double price, string region) = 0;
 99 };
100 class AFactory :public simpleFactory{
101 
102 public:
103     Product*createProduct(productType p, double price, string region){
104         Product*P;
105         Afactoryinformation*A = new Afactoryinformation();
106         A->setPrice(price);
107         A->setRegion(region);
108         switch (p){
109         case TYPE1: P = new ProductType1(A); break;
110         case TYPE2: P = new ProductType2(A); break;
111         case TYPE3: P = new ProductType3(A); break;
112         default:P = new ProductType4(A); break;
113         }
114         return P;
115     }
116 };
117 class BFactory :public simpleFactory{
118 
119 public:
120     Product*createProduct(productType p,double price,string region){
121         Product*P;
122         Bfactoryinformation*B = new Bfactoryinformation();
123         B->setPrice(price);
124         B->setRegion(region);
125         switch (p){
126         case TYPE1: P = new ProductType1(B); break;
127         case TYPE2: P = new ProductType2(B); break;
128         case TYPE3: P = new ProductType3(B); break;
129         default:P = new ProductType4(B); break;
130         }
131         return P;
132     }
133 };
134 void getIntroduce(){
135 
136     Product*P;
137     AFactory A;
138     BFactory B;
139     P = A.createProduct(TYPE1,10.0,"USA");
140     P->introduce();
141     delete P;
142     P = A.createProduct(TYPE2,20.0,"CN");
143     P->introduce();
144     delete P;
145     P = A.createProduct(TYPE3, 30.0, "RU");
146     P->introduce();
147     delete P;
148     P = A.createProduct(TYPE4, 15.0, "JP");
149     P->introduce();
150     delete P;
151     P = B.createProduct(TYPE1, 10.0, "USA");
152     P->introduce();
153     delete P;
154     P = B.createProduct(TYPE2, 56.0, "UK");
155     P->introduce();
156     delete P;
157     P = B.createProduct(TYPE3, 38.0, "PH");
158     P->introduce();
159     delete P;
160     P = B.createProduct(TYPE4, 9.0, "AUS");
161     P->introduce();
162     delete P;
163     return;
164 
165 }
166 int main(){
167     getIntroduce();
168     system("pause");
169     return 0;
170 }

  对于抽象工厂模式来说,创建一个新的产品族很简单,只需要新建工厂,但创建新的产品很麻烦,需要修改工厂类的代码。

总结:

工厂模式当中包含简单工厂模式,工厂模式和抽象工厂模式三种。理顺三种模式的联系和区别能让我们对工厂模式有更深刻的认识。

1.简单工厂模式是一种很简单的设计模式,它更像一种编程习惯。简单工厂将创建新对象的代码封装起来,专门用来生成具体对象。

2.工厂模式引入了工厂等级的概念,对生产的产品进行分类,将简单工厂生成具体类的功能交给多个子类去完成,解决了简单工厂过于臃肿的问题。

3.抽象工厂引入了产品族的概念,通过抽象工厂可以创建一系列相关联的具体对象。抽象工厂模式通过组合,解决了工厂模式类爆炸的问题。