工厂模式的主要作用就是封装对象的创建过程,使得程序员不必准确指定创建对象所需要的构造函数,这样做的一个好处就是增加了程序的可扩展性。由于每个面向对象应用程序的设计都需要创建对象,并且由于人们可能需要通过增加新的类型来扩展应用程序,工厂模式可能是最有用的设计模式之一。
总的来说,工厂模式主要分为三种类型:简单工厂模式、多态工厂模式、抽象工厂模式。这三种模式都属于设计模式中的创建行模式,他们多多少少在设计上有些相似之处,其最终的目的都是为了将对象的实例化部分取出来,进而优化系统的架构,增加程序的可扩展性,下面就这三种模式作对比。
- 简单工厂模式
正如这种模式的名字一样,简单的工厂模式只适用于相对较简单的业务情况下,主要用于小型或者后期需要扩展比较少的项目中。其由三种角色所组成:
- 抽象产品角色:主要是提供产品公用的接口,在C++中一般是由抽象类所组成(C++中不存在关键字interface);
- 具体产品角色:继承自抽象产品角色,主要是定义各个具体产品的规范,工厂类所创建的对象也是该角色的实例;
- 工厂角色:这是简单工厂模式的核心角色,一般含有一定的逻辑判断,根据不同的逻辑判断结果创造不同的产品;
其类图可以简单表示如下:
下面以简单的类子说明这种设计模式。
1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 //抽象产品角色,用于定义产品的接口规范 6 class Shape{ 7 public: 8 virtual void draw() = 0; 9 virtual void erase() = 0; 10 virtual ~Shape(); 11 }; 12 //具体产品类用于定义各自产品的规范 13 class Circle:public Shape{ 14 friend class ShapeFactory; 15 private: 16 Circle(); 17 public: 18 void draw(); 19 void erase(); 20 ~Circle(); 21 }; 22 23 class Square:public Shape{ 24 friend class ShapeFactory; 25 private: 26 Square(); 27 public: 28 void draw(); 29 void erase(); 30 ~Square(); 31 }; 32 33 class ShapeFactory{ 34 public: 35 static Shape* creatshape(string); 36 }; 37 38 Shape::~Shape(){ cout << "Shaper::~Shape()" << endl; } 39 40 Circle::Circle(){} 41 42 void Circle::draw(){ 43 cout << "Circle::draw()" << endl; 44 } 45 46 void Circle::erase(){ 47 cout << "Circle::erase()" << endl; 48 } 49 50 Circle::~Circle(){ 51 cout << "Circle::~Circle()" << endl; 52 } 53 54 Square::Square(){} 55 56 void Square::draw(){ 57 cout << "Square::draw()" << endl; 58 } 59 void Square::erase(){ 60 cout << "Square::erase()" << endl; 61 } 62 Square::~Square(){ 63 cout << "Square::~Square()" << endl; 64 } 65 66 Shape* ShapeFactory::creatshape(string id){ 67 if ("Circle" == id) 68 return new Circle; 69 else if ("Square" == id) 70 return new Square; 71 else 72 return nullptr; 73 } 74 75 int main() 76 { 77 string _circle("Circle"); 78 string _square("Square"); 79 80 Shape* ptr = ShapeFactory::creatshape(_circle); 81 ptr->draw(); 82 ptr->erase(); 83 84 ptr = ShapeFactory::creatshape(_square); 85 ptr->draw(); 86 ptr->erase(); 87 88 delete ptr; 89 }
其输出结果如下:
以上就是简单工厂模式了,这有什么好处呢?首先,将具体产品的构造函数声明为private属性,保证了不能直接构造函数的对象(这也是C++中创建单例模式的管用手段),也就是说隐藏了该对象的构建方式。通过将工厂类声明为具体的产品类的友元,保证了工厂类中可以调用具体产品类的构造函数,从而创建对象。客户程序员不需要使用具体的构造函数,所有对象的构造统一由工厂中的静态方法所执行。但是其缺点在于,如果堆shape增加新的具体的产品类,则需要不断的修改工厂模式中的条件判断语句。当产品的种类很少的时候这还是可以接受的,但是如果产品的种类很多,那么工厂类的静态方法中就会存在许多的条件分支。这也就是说简单工厂模式只适用于较小项目或者后期不需要扩展的项目中。
- 多态工厂模式
上面说明了简单工厂模式的具体组成及其优缺点,由于增加新的具体产品的时候,每次都需要修改工厂函数的实现,显然扩展性不是很好。而“四人帮”之所以强调工厂模式的理由则是,该模式可以使不同类型的工厂派生自基本类型的工厂。简单工厂模式其实是多态工厂模式的一个特例。那么多态工厂模式的组成部分有哪些呢?
- 抽象工厂角色:这是多态工厂方法的核心,该角色与具体的应用程序无关,是具体工厂角色所必须要继承的接口规范。在C++中一般是由抽象基类所组成;
- 具体工厂角色:含有和具体的业务逻辑有关的代码,由应用程序调用以创建具体的产品角色;
- 抽象产品角色:作为具体产品所必须遵守的接口规范和继承的基类;
- 具体产品角色:具体工厂角色所创建的就是该对象的实例;
该模式下所对应的UML图的类图如下:
下面还是用Shape的类子说明多态工厂模式的运行方式:
1 #include<iostream> 2 using namespace std; 3 4 //抽象产品角色,用于定义产品的接口规范 5 6 class Shape{ 7 public: 8 Shape(){ cout << "Shape::Shape()" << endl; } 9 virtual void draw() = 0; 10 virtual void erase() = 0; 11 virtual ~Shape(){ cout << "Shape::~Shape()" << endl; } 12 }; 13 14 15 //抽象工厂方法 16 class ShapeFactory{ 17 public: 18 ShapeFactory(){ cout << "ShapeFactory::ShapeFactory()" << endl; } 19 virtual ~ShapeFactory(){ cout << "ShapeFactory::~ShapeFactory()" << endl; } 20 virtual Shape* create() = 0; 21 }; 22 23 //具体产品类用于定义各自产品的规范 24 class Circle :public Shape{ 25 friend class CircleFactory; 26 private: 27 Circle(){ cout << "Circle::Circle()" << endl; } 28 public: 29 void draw(){ 30 cout << "Circle::draw()" << endl; 31 } 32 void erase(){ 33 cout << "Circle::erase()" << endl; 34 } 35 ~Circle(){ 36 cout << "Circle::~Circle()" << endl; 37 } 38 }; 39 40 class Square :public Shape{ 41 friend class SquareFactory; 42 private: 43 Square(){ cout << "Square::Square()" << endl; } 44 public: 45 void draw(){ 46 cout << "Square::draw()" << endl; 47 } 48 void erase(){ 49 cout << "Square::erase()" << endl; 50 } 51 ~Square(){ 52 cout << "Square::~Square()" << endl; 53 } 54 }; 55 56 class CircleFactory:public ShapeFactory{ 57 public: 58 CircleFactory(){ cout << "Circlefactory::CircleFactory()" << endl; } 59 Shape* create(){ 60 return new Circle; 61 } 62 ~CircleFactory(){ cout << "Circlefactory::~CircleFactory()" << endl; } 63 }; 64 65 class SquareFactory :public ShapeFactory{ 66 public: 67 SquareFactory(){ cout << "SquareFactory::~SquareFactory()" << endl; } 68 Shape* create(){ 69 return new Square; 70 } 71 ~SquareFactory(){ cout << "SquareFactory::~SquareFactory()" << endl; } 72 }; 73 74 int main() 75 { 76 Shape* Circleptr = CircleFactory().create(); 77 Shape* Squareptr = SquareFactory().create(); 78 79 Circleptr->draw(); 80 Circleptr->erase(); 81 82 Squareptr->draw(); 83 Squareptr->erase(); 84 85 delete Circleptr; 86 delete Squareptr; 87 88 }
其运行结果如下:
上述工厂方法中,每次增加新的类的时候只要增加新的产品类并增加其对应的工厂函数,然后重新编译运行即可。但是为了能够使工厂类的派生类从其基类中解耦,我们可以使用另一扩展方法,在这种方法中并不需要为每一个类生成一个对应的工厂的派生类,只需要基本的工厂函数维护一个包含类的类型以及与其创建所关联的函数的映射即可(如map容器)。可以通过增加几个新的函数用来注册和注销新的派生类,在运行的时候能注册新的类允许这种类型的工厂模式创建可扩展的接口。
在扩展的方式中不再需要为每个新的产品类增加一个新的工厂类,当增加新的产品类的时候,只需要实现产品的实现类并且将该产品类得创建函数注册到工厂类的map容器中即可。另一个需要注意的是工厂的对象必须保存对象,即最好只有一个工厂对象。这也是工厂对象通常是单件的原因。为了程序的简单明了,这里使用静态变量。废话少说,上代码:
1 #include<iostream> 2 #include<string> 3 #include<map> 4 using namespace std; 5 6 //抽象产品角色,用于定义产品的接口规范 7 8 class Shape{ 9 public: 10 Shape(){ cout << "Shape::Shape()" << endl; } 11 virtual void draw() = 0; 12 virtual void erase() = 0; 13 virtual ~Shape(){ cout << "Shape::~Shape()" << endl; } 14 }; 15 16 17 //抽象工厂方法 18 class ShapeFactory{ 19 public: 20 21 typedef Shape* (*create)(); 22 23 ShapeFactory(){ cout << "ShapeFactory::ShapeFactory()" << endl; } 24 virtual ~ShapeFactory(){ cout << "ShapeFactory::~ShapeFactory()" << endl; } 25 26 static void Register(const string& str, create ptr){ 27 createmap[str] = ptr; 28 cout << "ShapeFactory::Register()" << endl; 29 } 30 static void Unregister(const string& str){ 31 createmap.erase(str); 32 cout << "ShapeFactory::Unregister()" << endl; 33 } 34 static Shape* CreateShape(const string& str){ 35 cout << "ShapeFactory::CreateShape()" << endl; 36 map<string, create>::iterator iter = createmap.find(str); 37 if (iter != createmap.end()) 38 return (iter->second)(); 39 return nullptr; 40 } 41 private: 42 static map<string, create> createmap; 43 }; 44 45 //具体产品类用于定义各自产品的规范 46 class Circle :public Shape{ 47 private: 48 Circle(){ cout << "Circle::Circle()" << endl; } 49 public: 50 void draw(){ 51 cout << "Circle::draw()" << endl; 52 } 53 void erase(){ 54 cout << "Circle::erase()" << endl; 55 } 56 ~Circle(){ 57 cout << "Circle::~Circle()" << endl; 58 } 59 static Shape* create(){ 60 cout << "Circle::create()" << endl; 61 return new Circle; 62 } 63 }; 64 65 class Square :public Shape{ 66 private: 67 Square(){ cout << "Square::Square()" << endl; } 68 public: 69 void draw(){ 70 cout << "Square::draw()" << endl; 71 } 72 void erase(){ 73 cout << "Square::erase()" << endl; 74 } 75 ~Square(){ 76 cout << "Square::~Square()" << endl; 77 } 78 static Shape* create(){ 79 cout << "Square::create()" << endl; 80 return new Square; 81 } 82 }; 83 84 map<string, ShapeFactory::create> ShapeFactory::createmap; 85 int main() 86 { 87 ShapeFactory::Register("Circle",Circle::create); 88 ShapeFactory::Register("Square", Square::create); 89 90 Shape* ptr=ShapeFactory::CreateShape("Circle"); 91 92 ptr->draw(); 93 ptr->erase(); 94 95 //ShapeFactory::Unregister("Square");如果加上这句则会造成抛出异常,造成程序终止 96 ptr = ShapeFactory::CreateShape("Square"); 97 ptr->draw(); 98 ptr->erase(); 99 100 delete ptr; 101 }
其运行结果如下:
- 抽象工厂模式
抽象工厂模式看起来和前面的工厂方法类似,只是它使用若干的工厂方法模式。每个工厂方法模式创建一个不同类型的对象。当创建一个工厂对象的时候,要决定将如何使用由那个工厂创建的所有对象。其组成部分为:
- 抽象工厂角色:这是多态工厂方法的核心,该角色与具体的应用程序无关,是具体工厂角色所必须要继承的接口规范。在C++中一般是由抽象基类所组成;
- 具体工厂角色:含有和具体的业务逻辑有关的代码,由应用程序调用以创建具体的产品角色;
- 抽象产品角色:作为具体产品所必须遵守的接口规范和继承的基类;
- 具体产品角色:具体工厂角色所创建的就是该对象的实例;
其类图为:
下面是用一个类子说明抽象工厂模式。代码如下:
1 #include<iostream> 2 3 using namespace std; 4 5 class Obstacle{ 6 public: 7 virtual void action() = 0; 8 }; 9 10 class Player{ 11 public: 12 virtual void interactWith(Obstacle*) = 0; 13 }; 14 15 class Kitty :public Player{ 16 virtual void interactWith(Obstacle* ob){ 17 cout << "Kitty has encountered a "; 18 ob->action(); 19 } 20 }; 21 22 class Amy :public Player{ 23 virtual void interactWith(Obstacle* ob) 24 { 25 cout << "Amy has encountered a "; 26 ob->action(); 27 } 28 }; 29 30 class Puzzle :public Obstacle{ 31 public: 32 void action() 33 { 34 cout << "Puzzle" << endl; 35 } 36 }; 37 38 class NastyWeapon :public Obstacle{ 39 public: 40 void action() 41 { 42 cout << "NastyWeapon" << endl; 43 } 44 }; 45 46 class GameElementFactory{ 47 public: 48 virtual Player* makePlayer() = 0; 49 virtual Obstacle* makeObstacle() = 0; 50 }; 51 52 class KittyandPuzzle :public GameElementFactory{ 53 public: 54 Player* makePlayer(){ 55 return new Kitty; 56 } 57 Obstacle* makeObstacle(){ 58 return new Puzzle; 59 } 60 61 }; 62 63 class KillandDismember :public GameElementFactory{ 64 public: 65 Player* makePlayer(){ 66 return new Amy; 67 } 68 Obstacle* makeObstacle(){ 69 return new NastyWeapon; 70 } 71 72 }; 73 74 class GameEnvironment{ 75 GameElementFactory* gef; 76 Player* p; 77 Obstacle* ob; 78 public: 79 GameEnvironment(GameElementFactory* factory) :gef(factory), p(factory->makePlayer()), ob(factory->makeObstacle()){} 80 void play(){ 81 p->interactWith(ob); 82 } 83 ~GameEnvironment() 84 { 85 delete p; 86 delete ob;; 87 delete gef; 88 } 89 }; 90 91 92 int main(){ 93 GameEnvironment g1(new KittyandPuzzle), g2(new KillandDismember); 94 g1.play(); 95 g2.play(); 96 }
其运行结果如下:
抽象工厂模式一般是适用于多个产品族,所谓的产品族是指位于不同产品等级结构中,功能相关联的产品组成的家族。它和多态方法模式的区别就在于需要创建对象的复杂程度上。而且抽象工厂模式是三个里面最为抽象、最具一般性的。抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象。
而且使用抽象工厂模式还要满足一下条件:
1.系统中有多个产品族,而系统一次只可能消费其中一族产品
2.同属于同一个产品族的产品以其使用。
总结:
工厂模式可以极大地提高程序的可扩展性 ,根据程序的具体特点选择合适的工厂模式有助于后期 程序的扩展和维护!