Object Factory用以生成一个对象,Abstract Factory用以生成多个关联的对象。
对于Abstract Factory而言,它有两个问题造成耦合度太高。一是Abstract Factory必须知道所有Abstruct Product,具体工厂必须知道它要生成的所有具体类。
Loki的AF解决了这个问题,在这里,我关心它如何做到的。
对于AF的抽象接口,Loki如此处理:
class AFUnit
... {
public:
virtual T* DoCreate(Type2Type<T>) = 0;
virtual ~AFUnit();
} ;
你可能需要生成好几个类,但这没有问题,GenScatterHierarchy可以把这个类应用于所有的TList成员类型。明显,不同的类有不同的DoCreate方法,为了获得正确的函数调用,这个Type2Type必不可少。
Loki使用了极具威力的TypeList传递待生成的类信息:
<
class TList,
template < class > class Unit = AFUnit
>
class AbstractFactory : public GenscatterHierarchy < TList,Unit >
... {
public:
typedef TList ProductList;
template <class T>
T* Create()
...{
Unit<T>& unit = *this;
return unit.DoCreate(Type2Type<T>());
}
} ;
好极了,GenscatterHierarchy可以把Unit应用于每个TList中的类型。对于特定的类型T,使用特定的Unit的Docreate方法生成。其实Create是一个分派器,对于特定的类型通过它你可以获得对应的产品。在这种情况下,你可以把AbstractFactory转型为某个具体类型工厂传递给特定的生成模块。
譬如T类型的文件只关心生成T,所以你可以传递AbstractFactory<T>,该文件所要做的只是实现T的DoCreate方法。
到此我们对这个框架有了大致的理解,但是还是没有说明如何实现DoCreate,其实解决方法比想像中的要简单。
class OpNewFactoryUnit : public Base
... {
typedef typename Base::ProductList BaseProductList;
protected:
typedef typename BaseProductList::Tail ProductList;
public:
typedef typename BaseProductList::Head AbstractProduct;
ConcreteProduct* DoCreate(Type2Type<AbstractProduct>)
...{
return new ConcreteProduct;
}
} ;
如此所有产品都得到了DoCreate方法。但是有个问题,OpNewFactoryUnit的包含文件要知道所有的产品类。其实这不是问题,我们来看ConcretteFactory的实现再讨论这个问题:
template < class , class , > class Creator = OpNewFactoryUnit
class TList = typename AbstractFact::ProductList
>
class ConcreteFactory
: public GenLinearHierarchy < typename TL::Reverse < TList > ::Result,Creator,AbstractFact >
... {
public:
typedef typename AbstractFact::ProductList ProductList;
typedef TList ConcreteProductList;
} ;
首先一个问题,OpNewFactoryUnit在定义的时候不需要知道任何类,因为它只是操作模板参数,而它的使用地方是在ConcreteFactory中,这个时候一个参数就是TList,TList肯定知道需要的一切类,这个需要的代价就是文件包含。当然,OpNewFactoryUnit没有任何多于文件依赖。
上面代码也展示了具体工厂的实现。ConcreteFactory(最终)继承于AbstractFactory,所以获取产品的方法不会有任何修改。所以这里无需定义太多东西。而ConcreteFactory最后的继承于一个施加于OpNewFactoryUnit的TList作用的AbstractFactory。