在面向对象系统设计中经常遇到以下两类问题:
1)为了提高内聚(Cohesion)和松耦合(Coupling),我们经常会抽象出一些类的公共接口以形成抽象基类或者接口。这样我们可以通过声明一个指向基类的指针来指向实际的子类实现,达到了多态的目的。这里很容易出现的一个问题n多的子类继承自抽象基类,我们不得不在每次要用到子类的地方就编写诸如new ×××;的代码。这里带来两个问题1)客户程序员必须知道实际子类的名称(当系统复杂后,命名将是一个很不好处理的问题,为了处理可能的名字冲突,有的命名可能并不是具有很好的可读性和可记忆性,就姑且不论不同程序员千奇百怪的个人偏好了。),2)程序的扩展性和维护变得越来越困难。
2)还有一种情况就是在父类中并不知道具体要实例化哪一个具体的子类。这里的意思为:假设我们在类A中要使用到类B,B是一个抽象父类,在A中并不知道具体要实例化那一个B的子类,但是在类A的子类D中是可以知道的。在A中我们没有办法直接使用类似于new ×××的语句,因为根本就不知道×××是什么。
以上两个问题也就引出了Factory模式的两个最重要的功能:
1)定义创建对象的接口,封装了对象的创建;
2)使得具体化类的工作延迟到了子类中。
模式选择
我们通常使用Factory模式来解决上面给出的两个问题。在第一个问题中,我们经常就是声明一个创建对象的接口,并封装了对象的创建过程。Factory这里类似于一个真正意义上的工厂(生产对象)。在第二个问题中,我们需要提供一个对象创建对象的接口,并在子类中提供其具体实现(因为只有在子类中可以决定到底实例化哪一个类)。
第一中情况简单工厂模式的Factory的结构示意图为:
图1:Factory模式结构示意图1
图1所以的Factory模式经常在系统开发中用到,但是这并不是Factory模式的最大威力所在(因为这可以通过其他方式解决这个问题)。Factory模式不单是提供了创建对象的接口,其最重要的是延迟了子类的实例化(第二个问题),以下是这种情况的一个Factory,工厂方法模式的结构示意图:
图2:工厂方法模式
图2中关键中Factory模式的应用并不是只是为了封装对象的创建,而是要把对象的创建放到子类中实现:Factory中只是提供了对象创建的接口,其实现将放在Factory的子类ConcreteFactory中进行。这是图2和图1的区别所在。
下面是工厂方法模式的C++实现:
1 //Product.h 2 #ifndef _PRODUCT_H_ 3 #define _PRODUCT_H_ 4 class Product 5 { 6 public: 7 virtual ~Product() = 0; 8 protected: 9 Product(); 10 private: 11 }; 12 class ConcreteProduct:public Product 13 { 14 public: 15 ~ConcreteProduct(); 16 ConcreteProduct(); 17 protected: 18 private: 19 }; 20 #endif //~_PRODUCT_H_
1 //Product.cpp 2 #include "Product.h" 3 #include <iostream> 4 using namespace std; 5 Product::Product() 6 { 7 } 8 Product::~Product() 9 { 10 } 11 ConcreteProduct::ConcreteProduct() 12 { 13 cout<<"ConcreteProduct...."<<endl; 14 } 15 ConcreteProduct::~ConcreteProduct() 16 { 17 }
1 //Factory.h 2 #ifndef _FACTORY_H_ 3 #define _FACTORY_H_ 4 class Product; 5 class Factory 6 { 7 public: 8 virtual ~Factory() = 0; 9 virtual Product* CreateProduct() = 0; 10 protected: 11 Factory(); 12 private: 13 }; 14 class ConcreteFactory:public Factory 15 { 16 public: 17 ~ConcreteFactory(); 18 ConcreteFactory(); 19 Product* CreateProduct(); 20 protected: 21 private: 22 }; 23 #endif //~_FACTORY_H_
1 //Factory.cpp 2 #include "Factory.h" 3 #include "Product.h" 4 #include <iostream> 5 using namespace std; 6 Factory::Factory() 7 { 8 } 9 Factory::~Factory() 10 { 11 } 12 ConcreteFactory::ConcreteFactory() 13 { 14 cout<<"ConcreteFactory....."<<endl; 15 } 16 ConcreteFactory::~ConcreteFactory() 17 { 18 } 19 Product* ConcreteFactory::CreateProduct() 20 { 21 return new ConcreteProduct(); 22 }
1 //main.cpp 2 #include "Factory.h" 3 #include "Product.h" 4 int main(int argc,char* argv[]) 5 { 6 Factory* fac = new ConcreteFactory(); 7 Product* p = fac->CreateProduct(); 8 return 0; 9 }
示例代码中给出的是Factory模式解决父类中并不知道具体要实例化哪一个具体的子类的问题,至于为创建对象提供接口问题,可以由Factory中附加相应的创建操作例如Create***Product()即可。具体请参加讨论内容。
Factory模式也带来至少以下两个问题: 1)如果为每一个具体的ConcreteProduct类的实例化提供一个函数体,那么我们可能不得不在系统中添加了一个方法来处理这个新建的ConcreteProduct,这样Factory的接口永远就不肯能封闭(Close)。当然我们可以通过创建一个Factory的子类来通过多态实现这一点,但是这也是以新建一个类作为代价的。
2)在实现中我们可以通过参数化工厂方法,即给FactoryMethod()传递一个参数用以决定是创建具体哪一个具体的Product。当然也可以通过模板化避免1)中的子类创建子类,其方法就是将具体Product类作为模板参数,实现起来也很简单。可以看出,Factory模式对于对象的创建给予开发人员提供了很好的实现策略,但是Factory模式仅仅局限于一类类(就是说Product是一类,有一个共同的基类),如果我们要为不同类的类提供一个对象创建的接口,那就要用AbstractFactory了。
AbstactFactory模式(抽象工厂模式)要创建一组相关或者相互依赖的对象。
假设我们要开发一款游戏,当然为了吸引更多的人玩,游戏难度不能太大(让大家都没有信心了,估计游戏也就没有前途了),但是也不能太简单(没有挑战性也不符合玩家的心理)。于是我们就可以采用这样一种处理策略:为游戏设立等级,初级、中级、高级甚至有BT级。假设也是过关的游戏,每个关卡都有一些怪物(monster)守着,玩家要把这些怪物干掉才可以过关。作为开发者,我们就不得不创建怪物的类,然后初级怪物、中级怪物等都继承自怪物类(当然不同种类的则需要另创建类,但是模式相同)。在每个关卡,我们都要创建怪物的实例,例如初级就创建初级怪物(有很多种类)、中级创建中级怪物
AbstractFactory模式典型的结构图为:
C++实现代码如下:
//Product.h #ifndef _PRODUCT_H_ #define _PRODUCT_H_ class AbstractProductA { public: virtual ~AbstractProductA(); protected: AbstractProductA(); private: }; class AbstractProductB { public: virtual ~AbstractProductB(); protected: AbstractProductB(); private: }; class ProductA1:public AbstractProductA { public: ProductA1(); ~ProductA1(); protected: private: }; class ProductA2:public AbstractProductA { public: ProductA2(); ~ProductA2(); protected: private: }; class ProductB1:public AbstractProductB { public: ProductB1(); ~ProductB1(); protected: private: }; class ProductB2:public AbstractProductB { public: ProductB2(); ~ProductB2(); protected: private: }; #endif //~_PRODUCT_H_ECT_H_ //Product.cpp #include "Product.h" #include <iostream> using namespace std; AbstractProductA::AbstractProductA() { } AbstractProductA::~AbstractProductA() { } AbstractProductB::AbstractProductB() { } AbstractProductB::~AbstractProductB() { } ProductA1::ProductA1() { cout<<"ProductA1..."<<endl; } ProductA1::~ProductA1() { } ProductA2::ProductA2() { cout<<"ProductA2..."<<endl; } ProductA2::~ProductA2() { } ProductB1::ProductB1() { cout<<"ProductB1..."<<endl; } ProductB1::~ProductB1() { } ProductB2::ProductB2() { cout<<"ProductB2..."<<endl; } ProductB2::~ProductB2() { }
1 //AbstractFactory.h 2 #ifndef _ABSTRACTFACTORY_H_ 3 #define _ABSTRACTFACTORY_H_ 4 class AbstractProductA; 5 class AbstractProductB; 6 class AbstractFactory 7 { 8 public: 9 virtual ~AbstractFactory(); 10 virtual AbstractProductA* CreateProductA() = 0; 11 virtual AbstractProductB* CreateProductB() = 0; 12 protected: 13 AbstractFactory(); 14 private: 15 }; 16 class ConcreteFactory1:public AbstractFactory 17 { 18 public: 19 ConcreteFactory1(); 20 ~ConcreteFactory1(); 21 AbstractProductA* CreateProductA(); 22 AbstractProductB* CreateProductB(); 23 protected: 24 private: 25 }; 26 class ConcreteFactory2:public AbstractFactory 27 { 28 public: 29 ConcreteFactory2(); 30 ~ConcreteFactory2(); 31 AbstractProductA* CreateProductA(); 32 AbstractProductB* CreateProductB(); 33 protected: 34 private: 35 }; 36 #endif //~_ABSTRACTFACTORY_H_ 37 38 39 //AbstractFactory.cpp 40 #include "AbstractFactory.h" 41 #include "Product.h" 42 #include <iostream> 43 using namespace std; 44 AbstractFactory::AbstractFactory() 45 { 46 } 47 AbstractFactory::~AbstractFactory() 48 { 49 } 50 ConcreteFactory1::ConcreteFactory1() 51 { 52 } 53 ConcreteFactory1::~ConcreteFactory1() 54 { 55 } 56 AbstractProductA* ConcreteFactory1::CreateProductA() 57 { 58 return new ProductA1(); 59 } 60 AbstractProductB* ConcreteFactory1::CreateProductB() 61 { 62 return new ProductB1(); 63 } 64 ConcreteFactory2::ConcreteFactory2() 65 { 66 } 67 ConcreteFactory2::~ConcreteFactory2() 68 { 69 } 70 AbstractProductA* ConcreteFactory2::CreateProductA() 71 { 72 return new ProductA2(); 73 } 74 AbstractProductB* ConcreteFactory2::CreateProductB() 75 { 76 return new ProductB2(); 77 }
1 #include "AbstractFactory.h" 2 #include <iostream> 3 using namespace std; 4 int main(int argc,char* argv[]) 5 { 6 AbstractFactory* cf1 = new ConcreteFactory1(); 7 cf1->CreateProductA(); 8 cf1->CreateProductB(); 9 AbstractFactory* cf2 = new ConcreteFactory2(); 10 cf2->CreateProductA(); 11 cf2->CreateProductB(); 12 return 0; 13 }
AbstractFactory模式的实现代码很简单,在测试程序中可以看到,当我们要创建一组对象(ProductA1,ProductA2)的时候我们只用维护一个创建对象(ConcreteFactory1),大大简化了维护的成本和工作。
AbstractFactory模式和Factory模式的区别是初学(使用)设计模式时候的一个容易引起困惑的地方。实际上,AbstractFactory模式是为创建一组(有多类)相关或依赖的对象提供创建接口,而Factory模式正如我在相应的文档中分析的是为一类对象提供创建接口或延迟对象的创建到子类中实现。并且可以看到,AbstractFactory模式通常都是使用Factory模式实现(ConcreteFactory1)。