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