关闭

由AF再论template

496人阅读 评论(0) 收藏 举报

template的伟大魅力在于它的自动生成代码能力,基于template的技术,无论多么高深仰或多么花哨,只要你明白它的自动生成代码的本质,问题会好处理很多。

譬如AbstractFactory在template下的loki做法,它只是为了让编译器帮我们生成代码而已,如果你考虑手写代码,问题会好理解很多。

A抽象基类问题

如果你要使用AbstractFactory模式,那你首先要有一个基类,它定义了生成方法。Loki定义了如此一个接口:

template    <class T>
class    AFUnit
{
public:
    
virtual    T*    DoCreate(Type2Type<T>)    = 0;
    
virtual    ~AFUnit();
}
;

这是一个模板化的东西,明显,在不同的类参与作用下,这会被实例化出一系列类,这是与AF有悖的,毕竟AF我们希望使用统一一个基类,为了支持到这一点,Loki使用了强大的外星动力:GenScatterHierarchy。如此我们得到了一个统一的唯一的接口:

template
<
    
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>());
    }

}
;

尽管这个AbstractFactory是一个多类的组合体,只是它可以作为一个类使用处理,但这不仅仅保证了一个唯一的基类,还给我们提供了额外的优势——细粒度化,你可以对不同的模块传递它的不同颗粒,本模块不必知晓任何一点与自己无关的颗粒以及与该颗粒管理的类、包含关系。

我们回顾AF模式,它要求基类只需要提供统一接口。ok,这个AbstractFactory已经满足这个要求了。使用AF的时候抽象基类问题到此得到完美解决。

B子类实现问题

AF有几个要求,子类要继承基类,并且实现基类的方法,子类也应该是一个唯一的类。

基类已经是一个多颗粒的东西,子类必然是多颗粒的,单又要都继承于AbstractorFactory而且又要保证自己的外观是单颗粒的,只有逐一继承最后包装,GenLinearHierarchy可以帮上这个忙,它可以产出都继承于某一类的类(如果你习惯使用loki的时候使用默认参数,我建议你要多全部参数的声明有个了解),而且它可以对TList操作,不要忘记,AbstractFactory也使用了TList,使用同样的TList可以使你得到完美的继承体系。

满足了继承关系,还要重写基类的虚函数,使用policy是个不错的选择,为继承体系中的每个类都加入一个实现了虚函数的policy,这样每个类都有了虚函数的实现,而每个类又恰恰继承于基类,这简直太完美了,巧合还是人为?难以一言蔽之。

template    <class AbstractFact,
            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;
}
;

使用TL和Creator创建继承于AbstractFact的线性类表,而ConcreteFactory继承于这个线性表,或者可以说ConcreteFactory是对多颗粒的一个单粒度封装。还是太完美了。

到这里实现Creator规则太简单了。

template    <class ConcreteProduct,class Base>
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;
    }

}
;

Creator没有什么特别的,按照指定规则做事而已。

到这里AF已经被Loki包装成完全自动生成代码的东西了,你只需提供少量的信息,就可以批量获取产品,这才是工厂。

    typedef    AbstractFactory<LOKI_TYPELIST_3(Base,Test1,Test2)>    MyKit;
    
//MyKit*    pKit    = new    MyKit;
    
//Test2*    t2    = pKit->Create<Test2>();

    typedef    ConcreteFactory
<MyKit>    MyConKit;

    MyConKit
*    pKit    = new    MyConKit;
    SmartPtr
<Test2>    t2    = pKit->Create<Test2>();
    t2
->say();
    SmartPtr
<Test1>    t3    = pKit->Create<Test1>();
    t3
->say();

不管如何美化,template还是为了生成代码,这是它的本质,用这个本质考虑template参与情况下的问题会容易理解很多。分析使用AF的时候的逐个细节并归纳,你也可以完成这些。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:181140次
    • 积分:2934
    • 等级:
    • 排名:第12547名
    • 原创:113篇
    • 转载:3篇
    • 译文:0篇
    • 评论:28条
    文章分类