工厂模式属于创建型模式,大致可以分为三类,简单工厂模式、工厂方法模式、抽象工厂模式。
通过两个例子讲解这三种工厂模式
示例一
简单工厂模式
首先介绍简单工厂模式,它的主要特点是需要在工厂类中做判断,从而创造相应的产品。当增加新的产品时,就需要修改工厂类。有点抽象,举个例子就明白了。有一家生产处理器核的厂家,它只有一个工厂,能够生产两种型号的处理器核。客户需要什么样的处理器核,一定要显示地告诉生产工厂。下面给出一种实现方案。
1 enum CTYPE {COREA, COREB}; 2 class SingleCore 3 { 4 public: 5 virtual void Show() = 0; 6 }; 7 //单核A 8 class SingleCoreA: public SingleCore 9 { 10 public: 11 void Show() { cout<<"SingleCore A"<<endl; } 12 }; 13 //单核B 14 class SingleCoreB: public SingleCore 15 { 16 public: 17 void Show() { cout<<"SingleCore B"<<endl; } 18 }; 19 //唯一的工厂,可以生产两种型号的处理器核,在内部判断 20 class Factory 21 { 22 public: 23 SingleCore* CreateSingleCore(enum CTYPE ctype) 24 { 25 if(ctype == COREA) //工厂内部判断 26 return new SingleCoreA(); //生产核A 27 else if(ctype == COREB) 28 return new SingleCoreB(); //生产核B 29 else 30 return NULL; 31 } 32 };
工厂方法模式
这样设计的主要缺点之前也提到过,就是要增加新的核类型时,就需要修改工厂类。这就违反了开放封闭原则:软件实体(类、模块、函数)可以扩展,但是不可修改。于是,工厂方法模式出现了。所谓工厂方法模式,是指定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。
听起来很抽象,还是以刚才的例子解释。这家生产处理器核的产家赚了不少钱,于是决定再开设一个工厂专门用来生产B型号的单核,而原来的工厂专门用来生产A型号的单核。这时,客户要做的是找好工厂,比如要A型号的核,就找A工厂要;否则找B工厂要,不再需要告诉工厂具体要什么型号的处理器核了。下面给出一个实现方案。
1 class SingleCore 2 { 3 public: 4 virtual void Show() = 0; 5 }; 6 //单核A 7 class SingleCoreA: public SingleCore 8 { 9 public: 10 void Show() { cout<<"SingleCore A"<<endl; } 11 }; 12 //单核B 13 class SingleCoreB: public SingleCore 14 { 15 public: 16 void Show() { cout<<"SingleCore B"<<endl; } 17 }; 18 class Factory 19 { 20 public: 21 virtual SingleCore* CreateSingleCore() = 0; 22 }; 23 //生产A核的工厂 24 class FactoryA: public Factory 25 { 26 public: 27 SingleCoreA* CreateSingleCore() { return new SingleCoreA; } 28 }; 29 //生产B核的工厂 30 class FactoryB: public Factory 31 { 32 public: 33 SingleCoreB* CreateSingleCore() { return new SingleCoreB; } 34 };
抽象工厂模式
工厂方法模式也有缺点,每增加一种产品,就需要增加一个对象的工厂。如果这家公司发展迅速,推出了很多新的处理器核,那么就要开设相应的新工厂。在C++实现中,就是要定义一个个的工厂类。显然,相比简单工厂模式,工厂方法模式需要更多的类定义。
既然有了简单工厂模式和工厂方法模式,为什么还要有抽象工厂模式呢?它到底有什么作用呢?还是举这个例子,这家公司的技术不断进步,不仅可以生产单核处理器,也能生产多核处理器。现在简单工厂模式和工厂方法模式都鞭长莫及。抽象工厂模式登场了。它的定义为提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。具体这样应用,这家公司还是开设两个工厂,一个专门用来生产A型号的单核多核处理器,而另一个工厂专门用来生产B型号的单核多核处理器,下面给出实现的代码。
1 //单核 2 class SingleCore 3 { 4 public: 5 virtual void Show() = 0; 6 }; 7 class SingleCoreA: public SingleCore 8 { 9 public: 10 void Show() { cout<<"Single Core A"<<endl; } 11 }; 12 class SingleCoreB :public SingleCore 13 { 14 public: 15 void Show() { cout<<"Single Core B"<<endl; } 16 }; 17 //多核 18 class MultiCore 19 { 20 public: 21 virtual void Show() = 0; 22 }; 23 class MultiCoreA : public MultiCore 24 { 25 public: 26 void Show() { cout<<"Multi Core A"<<endl; } 27 28 }; 29 class MultiCoreB : public MultiCore 30 { 31 public: 32 void Show() { cout<<"Multi Core B"<<endl; } 33 }; 34 //工厂 35 class CoreFactory 36 { 37 public: 38 virtual SingleCore* CreateSingleCore() = 0; 39 virtual MultiCore* CreateMultiCore() = 0; 40 }; 41 //工厂A,专门用来生产A型号的处理器 42 class FactoryA :public CoreFactory 43 { 44 public: 45 SingleCore* CreateSingleCore() { return new SingleCoreA(); } 46 MultiCore* CreateMultiCore() { return new MultiCoreA(); } 47 }; 48 //工厂B,专门用来生产B型号的处理器 49 class FactoryB : public CoreFactory 50 { 51 public: 52 SingleCore* CreateSingleCore() { return new SingleCoreB(); } 53 MultiCore* CreateMultiCore() { return new MultiCoreB(); } 54 };
示例二
简单工厂模式
问题描述
之前在公司做了一个windows 8平台的阅读器。首先,需要将电子书中的内容渲染到屏幕上,而电子书每一页都包含各种各样的内容,比如:图形、图像和文字等等;不同的内容,就是不同的对象;在将不同的内容渲染到屏幕上之前,就需要new操作,建立不同的对象,然后再在屏幕上进行描绘。这个时候,就需要进行很多new操作,new操作分布在代码的不同地方,管理起来很麻烦,而且也很乱,到后期扩展和维护的时候,有的时候,对象多的让开发人员不知道这个对象是干什么的,这就增加了难度;同时,new操作,都会有对应的异常处理,最后,就会发现,在代码中,new了一个对象,然后,就跟着一段异常处理代码,这时编码变的极其混乱和臃肿。那么怎么办?怎么办?此时,我们需要一个新的类,专门从事对象的建立和释放,之后,对象的各种操作,和这个类没有任何关系。这个专门建立对象的类,向外暴漏创建对象的接口,供外部调用。
工厂模式有一种非常形象的描述,建立对象的类就如一个工厂,而需要被建立的对象就是一个个产品;在工厂中加工产品,使用产品的人,不用在乎产品是如何生产出来的。从软件开发的角度来说,这样就有效的降低了模块之间的耦合。
适用场合
- 在程序中,需要创建的对象很多,导致对象的new操作多且杂时,需要使用简单工厂模式;
- 由于对象的创建过程是我们不需要去关心的,而我们注重的是对象的实际操作,所以,我们需要分离对象的创建和操作两部分,如此,方便后期的程序扩展和维护。
1 #include <iostream> 2 #include <vector> 3 using namespace std; 4 5 typedef enum ProductTypeTag 6 { 7 TypeA, 8 TypeB, 9 TypeC 10 }PRODUCTTYPE; 11 12 // Here is the product class 13 class Product 14 { 15 public: 16 virtual void Show() = 0; 17 }; 18 19 class ProductA : public Product 20 { 21 public: 22 void Show() 23 { 24 cout<<"I'm ProductA"<<endl; 25 } 26 }; 27 28 class ProductB : public Product 29 { 30 public: 31 void Show() 32 { 33 cout<<"I'm ProductB"<<endl; 34 } 35 }; 36 37 class ProductC : public Product 38 { 39 public: 40 void Show() 41 { 42 cout<<"I'm ProductC"<<endl; 43 } 44 }; 45 46 // Here is the Factory class 47 class Factory 48 { 49 public: 50 Product* CreateProduct(PRODUCTTYPE type) 51 { 52 switch (type) 53 { 54 case TypeA: 55 return new ProductA(); 56 57 case TypeB: 58 return new ProductB(); 59 60 case TypeC: 61 return new ProductC(); 62 63 default: 64 return NULL; 65 } 66 } 67 }; 68 69 int main(int argc, char *argv[]) 70 { 71 // First, create a factory object 72 Factory *ProductFactory = new Factory(); 73 Product *productObjA = ProductFactory->CreateProduct(TypeA); 74 if (productObjA != NULL) 75 productObjA->Show(); 76 77 Product *productObjB = ProductFactory->CreateProduct(TypeB); 78 if (productObjB != NULL) 79 productObjB->Show(); 80 81 Product *productObjC = ProductFactory->CreateProduct(TypeC); 82 if (productObjC != NULL) 83 productObjC->Show(); 84 85 delete ProductFactory; 86 ProductFactory = NULL; 87 88 delete productObjA; 89 productObjA = NULL; 90 91 delete productObjB; 92 productObjB = NULL; 93 94 delete productObjC; 95 productObjC = NULL; 96 97 return 0; 98 }
工厂方法模式
问题描述
由于简单工厂模式的局限性,比如:工厂现在能生产ProductA、ProductB和ProductC三种产品了,此时,需要增加生产ProductD产品;那么,首先是不是需要在产品枚举类型中添加新的产品类型标识,然后,修改Factory类中的switch结构代码。是的,这种对代码的修改,对原有代码的改动量较大,易产生编码上的错误(虽然很简单,如果工程大了,出错也是在所难免的!!!)。这种对代码的修改是最原始,最野蛮的修改,本质上不能称之为对代码的扩展。同时,由于对已经存在的函数进行了修改,那么以前进行过的测试,都将是无效的,所有的测试,都将需要重新进行,所有的代码都需要进行重新覆盖。这种,增加成本,不能提高效率的事情,在公司是绝对不允许的(除非昏庸的PM)。出于种种原因,简单工厂模式,在实际项目中使用的较少。那么该怎么办?怎么办呢?需要对原有代码影响降到最小,同时能对原有功能进行扩展。
适用场合
工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
- 在设计的初期,就考虑到产品在后期会进行扩展的情况下,可以使用工厂方法模式;
- 产品结构较复杂的情况下,可以使用工厂方法模式;
由于使用设计模式是在详细设计时,就需要进行定夺的,所以,需要权衡多方面的因素,而不能为了使用设计模式而使用设计模式。
1 #include <iostream> 2 using namespace std; 3 4 class Product 5 { 6 public: 7 virtual void Show() = 0; 8 }; 9 10 class ProductA : public Product 11 { 12 public: 13 void Show() 14 { 15 cout<< "I'm ProductA"<<endl; 16 } 17 }; 18 19 class ProductB : public Product 20 { 21 public: 22 void Show() 23 { 24 cout<< "I'm ProductB"<<endl; 25 } 26 }; 27 28 class Factory 29 { 30 public: 31 virtual Product *CreateProduct() = 0; 32 }; 33 34 class FactoryA : public Factory 35 { 36 public: 37 Product *CreateProduct() 38 { 39 return new ProductA (); 40 } 41 }; 42 43 class FactoryB : public Factory 44 { 45 public: 46 Product *CreateProduct() 47 { 48 return new ProductB (); 49 } 50 }; 51 52 int main(int argc , char *argv []) 53 { 54 Factory *factoryA = new FactoryA (); 55 Product *productA = factoryA->CreateProduct(); 56 productA->Show(); 57 58 Factory *factoryB = new FactoryB (); 59 Product *productB = factoryB->CreateProduct(); 60 productB->Show(); 61 62 if (factoryA != NULL) 63 { 64 delete factoryA; 65 factoryA = NULL; 66 } 67 68 if (productA != NULL) 69 { 70 delete productA; 71 productA = NULL; 72 } 73 74 if (factoryB != NULL) 75 { 76 delete factoryB; 77 factoryB = NULL; 78 } 79 80 if (productB != NULL) 81 { 82 delete productB; 83 productB = NULL; 84 } 85 return 0; 86 }
抽象工厂模式
问题描述
由于工厂方法模式创建的对象都是继承于Product的,所以工厂方法模式中,每个工厂只能创建单一种类的产品,当需要生产一种全新的产品(不继承自Product)时,发现工厂方法是心有余而力不足。
举个例子来说:一个显示器电路板厂商,旗下的显示器电路板种类有非液晶的和液晶的;这个时候,厂商建造两个工厂,工厂A负责生产非液晶显示器电路板,工厂B负责生产液晶显示器电路板;工厂一直就这样运行着。有一天,总经理发现,直接生产显示器的其余部分也挺挣钱,所以,总经理决定,再建立两个工厂C和D;C负责生产非液晶显示器的其余部件,D负责生产液晶显示器的其余部件。此时,旁边参谋的人就说了,经理,这样做不好,我们可以直接在工厂A中添加一条负责生产非液晶显示器的其余部件的生产线,在工厂B中添加一条生产液晶显示器的其余部件的生产线,这样就可以不用增加厂房,只用将现有厂房进行扩大一下,同时也方便工厂的管理,而且生产非液晶显示器电路板的技术人员对非液晶显示的其余部件的生产具有指导的作用,生产液晶显示器电路板也是同理。总经理发现这是一个不错的主意。
再回到软件开发的过程中来,工厂A和B就是之前所说的工厂方法模式;总经理再次建立工厂C和D,就是重复工厂方法模式,只是生产的产品不同罢了。这样做的弊端就如参谋所说的那样,增加了管理成本和人力成本。在面向对象开发的过程中,是很注重对象管理和维护的,对象越多,就越难进行管理和维护;如果工厂数量过多,那么管理和维护的成本将大大增加;虽然生产的是不同的产品,但是可以二者之间是有微妙的关系的,如参谋所说,技术人员的一些技术经验是可以借鉴的,这就相当于同一个类中的不同对象,之间是可以公用某些资源的。那么,增加一条流水线,扩大厂房,当然是最好的主意了。
实际问题已经得到了解决,那么如何使用设计模式模拟这个实际的问题呢?那就是接下来所说的抽象工厂模式。
适用场合
工厂方法模式适用于产品种类结构单一的场合,为一类产品提供创建的接口;而抽象工厂方法适用于产品种类结构多的场合,主要用于创建一组(有多个种类)相关的产品,为它们提供创建的接口;就是当具有多个抽象角色时,抽象工厂便可以派上用场。
1 #include <iostream> 2 using namespace std; 3 4 // Product A 5 class ProductA 6 { 7 public: 8 virtual void Show() = 0; 9 }; 10 11 class ProductA1 : public ProductA 12 { 13 public: 14 void Show() 15 { 16 cout<<"I'm ProductA1"<<endl; 17 } 18 }; 19 20 class ProductA2 : public ProductA 21 { 22 public: 23 void Show() 24 { 25 cout<<"I'm ProductA2"<<endl; 26 } 27 }; 28 29 // Product B 30 class ProductB 31 { 32 public: 33 virtual void Show() = 0; 34 }; 35 36 class ProductB1 : public ProductB 37 { 38 public: 39 void Show() 40 { 41 cout<<"I'm ProductB1"<<endl; 42 } 43 }; 44 45 class ProductB2 : public ProductB 46 { 47 public: 48 void Show() 49 { 50 cout<<"I'm ProductB2"<<endl; 51 } 52 }; 53 54 // Factory 55 class Factory 56 { 57 public: 58 virtual ProductA *CreateProductA() = 0; 59 virtual ProductB *CreateProductB() = 0; 60 }; 61 62 class Factory1 : public Factory 63 { 64 public: 65 ProductA *CreateProductA() 66 { 67 return new ProductA1(); 68 } 69 70 ProductB *CreateProductB() 71 { 72 return new ProductB1(); 73 } 74 }; 75 76 class Factory2 : public Factory 77 { 78 ProductA *CreateProductA() 79 { 80 return new ProductA2(); 81 } 82 83 ProductB *CreateProductB() 84 { 85 return new ProductB2(); 86 } 87 }; 88 89 int main(int argc, char *argv[]) 90 { 91 Factory *factoryObj1 = new Factory1(); 92 ProductA *productObjA1 = factoryObj1->CreateProductA(); 93 ProductB *productObjB1 = factoryObj1->CreateProductB(); 94 95 productObjA1->Show(); 96 productObjB1->Show(); 97 98 Factory *factoryObj2 = new Factory2(); 99 ProductA *productObjA2 = factoryObj2->CreateProductA(); 100 ProductB *productObjB2 = factoryObj2->CreateProductB(); 101 102 productObjA2->Show(); 103 productObjB2->Show(); 104 105 if (factoryObj1 != NULL) 106 { 107 delete factoryObj1; 108 factoryObj1 = NULL; 109 } 110 111 if (productObjA1 != NULL) 112 { 113 delete productObjA1; 114 productObjA1= NULL; 115 } 116 117 if (productObjB1 != NULL) 118 { 119 delete productObjB1; 120 productObjB1 = NULL; 121 } 122 123 if (factoryObj2 != NULL) 124 { 125 delete factoryObj2; 126 factoryObj2 = NULL; 127 } 128 129 if (productObjA2 != NULL) 130 { 131 delete productObjA2; 132 productObjA2 = NULL; 133 } 134 135 if (productObjB2 != NULL) 136 { 137 delete productObjB2; 138 productObjB2 = NULL; 139 } 140 }
参考:
http://blog.csdn.net/wuzhekai1985/article/details/6660462