zoukankan      html  css  js  c++  java
  • <学习笔记>Algorithm Library Design 算法库设计in c++ IV(GenVoca 架构)

    GenVoca 架构

    GenVoca是一种软件架构,与policy-based架构类似的是,它的最终成品也是由各个组件组装而成的,但是组织的方式有所不同。

    在Policy-based架构中,组件作为具体的policy实现被添加到host class以实现相应的功能,而在GenVoca中组件作为wrappers (layers) on top of a more basic components adding functionality to it.

    个人感觉从原文给的list的一个实现来看,与基于policy的架构相比,GenVoca多了不同的层次,上层需要下层的不同实现。如B层需要下面的C来实现,而实现后的B又可作为实现提供给更上层的A。

    R : A | B[R]
    S : C[R] | D[S] | E[R,S]
    R可以由A实现,或者由B和R的一个实现合起来实现。
    S可以由C以及R的某个实现,合起来实现。

    GenVoca实例:List

    image

    上图是一个List的特征图。特征是从用户使用角度来看的,用户装配List要提供的参数。

    必要的特征

    我需要List 操纵什么样的数据?

    List如何持有数据?通过引用持有还是深拷贝的方法持有。

    对于数据操作,我们采用多态性吗?

    可选的特征

    需要一个变量记录长度吗->如果需要长度的数据类型是什么int short 还是long

    需要Tracing吗,这里意思是说我们要追踪过程打印过程信息吗?

    设计一个GenVoca架构需要考虑下面几个步骤:
    • 确定特种图中提到的主要职责,要提供的主要功能。对于List:
      • 数据的存储
      • 数据的拷贝
      • 数据的销毁(注意这个对应到特征图,如果用户选择copy持有数据,或者owned reference那么要自己负责delete,否则不需要,empty delete就好)
      • 动态类型检查(为了monomorphism)
      • 长度计数器
      • tracing
    • 确定组件分组:
      • BasicList: PtrList     //:左边代表策略组件,右边是不同的实现策略categories : components
      • Copier: PolymorphicCopier, MonomorphicCopier, EmptyCopier
      • Desroyer: ElementDestroyer, EmptyDestroyer
      • TypeChecker: DynamicTypeChecker, EmptyTypeChecker
      • Counter: LengthList
      • Tracing: TracedList
    • 确定使用依赖`use'' dependencies between component categories.

       image

    • Sort the categories into a layered architecture.得到具体架构。最底层的copier,destoryer,typechecker,作为config.

    The component categories that do not depend on other categories are grouped into the bottom ConfigurationRepository (Config for short) layer category.

    Tracing和Counter是可选的分组。

    个人注,上图其实很清楚的标明了List的整体架构设计。

    BasicList(其实就是用PtrList类实现)有3个策略copier,destoryer,typecheker,通过选择不同的策略组合不同的list。其实就是基于policy的设计。

    然后counter用basicList

    那么采用模版继承的方法。

    <typename Base>

    class Derived: public Base

    通过把basicList作为模版参数,并继承,使得counter复用basiclist,同时它自己提供basicList没有的长度计数器,修改相应操作维护长度计数。

    Tracing 使用counter那它在最上层,同样通过相同方式继承Counter即可,然后修改相应操作添加过程打印的信息。

    • 写下GenVoca grammar
    List            : TracedList[OptCounterList] | OptCounterList
    OptCounterList  : LengthList[BasicList] | BasicList
    BasicList       : PtrList[Config]
    Config          :
       Copier       : PolymorphicCopier | MonomorphicCopier | EmptyCopier
       Destroyer    : ElementDestroyer | EmptyDestroyer
       TypeChecker  : DynamicTypeChecker | EmptyTypeChecker
       ElementType  : [ElementType]
       LengthType   : int | short | long | ...
    实现细节

    用户可以自己定义一个符合自己需求的的config

    struct TracedIntListConfig {
      typedef int                             ElementType;
      typedef const ElementType               ElementArgumentType;
      typedef MonomorphicCopier<ElementType>  Copier;
      typedef ElementDestroyer<ElementType>   Destroyer;
      typedef DynamicTypeChecker<ElementType> TypeChecker;
    
      typedef TracedList<PtrList<TracedIntlListConfig> >
          FinalListType;
    };
    typedef TracedIntListConfig::FinalListType TracedIntList;
    这里要注意的是出现了模版参数循环依赖。这样才能给出具体的最终List类型。
    注,其实这个config不应该是最终提供给用户,这些参数是最终决定List类型的,但不应由用户设定这样的参数,这个还是一个比较内部的config,例如具体采用什么Destroyer对于用户应该是透明的。
    用户可能会设置出使用MonomorphicCopierEmptyDestroyer这样会带来内存泄漏的错误配置。
    这里面应该多一层抽象层,隔离开来。用户只要声明我用copy持有数据,或者说我用ownwed refernce,那么库的内部就会决定使用ElementDestroyer。
    而用户声明要使用external refernce持有数据的话,库的内部就会决定使用EmptyDestroyer,不做显示的delete,即我不负责数据的释放。
    后面会给出如何加上这一层抽象,所谓的Generator方法,让用户更高层次的设定参数。
     
    OK,我们先实现出一个基本的PtrList,这是一个最基本的list,它有很多策略参数,具体策略的实现用户给出在Config中。
    template <class Config_>
    class PtrList
    {
    public:
      // export Config
      typedef Config_ Config;
      
    private:
      // retrieve the needed types from the repository
      typedef typename Config::ElementType          ElementType;
      typedef typename Config::ElementArgumentType  ElementArgumentType;
      typedef typename Config::Copier               Copier;
      typedef typename Config::Destroyer            Destroyer;
      typedef typename Config::TypeChecker          TypeChecker;
      typedef typename Config::FinalListType        FinalListType;
    
      // data members
      ElementType*   head_;
      FinalListType* tail_;   // note: not PtrList* but FinalListType*
    
    public:
    
      PtrList (ElementArgumentType& h, FinalListType *t = 0)
        : head_(0), tail_(t) { set_head(h); }
    
      ~PtrList() { Destroyer::destroy(head_); }
    
      void set_head(ElementArgumentType& h) {
        TypeChecker::check(h);
        head_ = Copier::copy(h);
      }
    
      ElementType& head() { return *head_; }
    
      void set_tail(FinalListType *t) { tail_ = t; }
    
      FinalListType* tail() const { return tail_; }
    
    };
    

    //对这个最基本的list的使用

    template <class List>
    void print_list(List* l) {
      std::cout << "[ ";
      for ( ; l; l = l->tail() ) std::cout << l->head() << " ";
      std::cout << "]\n";
    }
    
    template <class List>
    void push_front(typename List::ElementArgumentType& e, List*& l) {
      l = new List(e, l);
    }
    
    int main()
    {
      typedef ListConfig::FinalListType List;
      List* ls = 0;
      push_front(1,ls);
      push_front(2,ls);
      push_front(3,ls);
      print_list(ls);   // prints "3 2 1"
    }

    注意list的实现中将一些操作转交给别的类去做,也即某些策略参数,如Copier,Destoyer

    template <class ElementType>
    struct MonomorphicCopier {
      static ElementType* copy(const ElementType& e) { 
        return new ElementType(e);
      }
    };
    
    template <class ElementType>
    struct PolymorphicCopier {
      static ElementType* copy(const ElementType& e) { 
        return e.clone();    // polymorphic copy using 
      }                      // virtual member function clone()
    };
    
    template <class ElementType>
    struct EmptyCopier {
      static ElementType* copy(ElementType& e) {   // note: not const
        return &e;       // no copy
      }
    };
    template <class ElementType>
    struct ElementDestroyer {
      static void destroy(ElementType* e) { delete e; }
    };
    
    template <class ElementType>
    struct EmptyDestroyer {
      static void destroy(ElementType* e) {}  // do nothing
    };
    
    template <class ElementType>
    struct DynamicTypeChecker {
      static void check(const ElementType& e) { 
        assert(typeid(e)==typeid(ElementType));
      }
    };
    
    template <class ElementType>
    struct EmptyTypeChecker {
      static void check(const ElementType& e) {}
    };
     
    最后更上层的laer采用inheritance-based wrappers实现。如LengthList
    template <class BasicList>
    class LengthList : public BasicList
    {
    public:
      // export config
      typedef typename BasicList::Config Config;
    
    private:
      // retrieve the needed types from the repository
      typedef typename Config::ElementType          ElementType;
      typedef typename Config::ElementArgumentType  ElementArgumentType;
      typedef typename Config::LengthType           LengthType;
      typedef typename Config::FinalListType        FinalListType;
    
      LengthType length_;
    
      LengthType compute_length() const {
        return tail() ? tail()->length()+1 : 1;
      }
    
    public:
    
      LengthList (ElementArgumentType& h, FinalListType *t = 0)
        : BasicList(h, t) {
        length_ = compute_length();
      }
    
      void set_tail(FinalListType *t) {
        BasicList::set_tail(t);
        length_ = compute_length();
      }
    
      LengthType length() const { return length_; }
    
    };
    Generators

    下面给出为了给用户更好的设置接口,进行抽象的方法。

    enum Ownership {ext_ref, own_ref, cp};
    enum Morphology {mono, poly};
    enum CounterFlag {with_counter, no_counter};
    enum TracingFlag {with_tracing, no_tracing};
    上面是用户需要知道的,他们所应该关心的List配置参数。
    template <bool condition, class Then, class Else>
    struct IF {
      typedef Then RET;
    };
    
    template <class Then, class Else>
    struct IF<false, Then, Else> {
      typedef Else RET;
    };

    上面是利用模版偏特化,编译期间选择类型的一种技巧。

    下面是具体的Generator的实现

    template <
      class       ElementType_,
      Ownership   ownership    = cp,
      Morphology  morphology   = mono,
      CounterFlag counter_flag = no_counter,
      TracingFlag tracing_flag = no_tracing,
      class       LengthType_  = int
    >
    class LIST_GENERATOR
    {
    public:
    
      // forward declaration of the configuration repository
      struct Config;
    
    private:
    
      // define the constants used for type selection
      enum {
        is_copy      = ownership==cp,
        is_own_ref   = ownership==own_ref,
        is_mono      = morphology==mono,
        has_counter  = counter_flag==with_counter,
        does_tracing = tracing_flag==with_tracing 
      };
    
      // select the components
      typedef typename
      IF<is_copy || is_own_ref,
         ElementDestroyer<ElementType_>,
         EmptyDestroyer<ElementType_>
      >::RET Destroyer_;
    
      typedef typename
      IF<is_mono,
         DynamicTypeChecker<ElementType_>,
         EmptyTypeChecker<ElementType_>
      >::RET TypeChecker_;
    
      typedef typename
      IF<is_copy,
         typename 
         IF<is_mono,
    	MonomorphicCopier<ElementType_>,
    	PolymorphicCopier<ElementType_> >::RET,
         EmptyCopier<ElementType_>
      >::RET Copier_;
    
      typedef typename
      IF<is_copy,
         const ElementType_,
         ElementType_
      >::RET ElementArgumentType_;
    
      // define the list type
      typedef PtrList<Config> BasicList;
    
      typedef typename
      IF<has_counter,
         LengthList<BasicList>,
         BasicList
      >::RET OptLengthList;
    
      typedef typename
      IF<does_tracing,
         TracedList<OptLengthList>,
         OptLengthList
      >::RET List;
    
    public:
    
      // return the final list type
      typedef List RET;
    
      // define the configuration repository
      struct Config {
        typedef ElementType_           ElementType;
        typedef ElementArgumentType_   ElementArgumentType;
        typedef Copier_                Copier;
        typedef Destroyer_             Destroyer;
        typedef TypeChecker_           TypeChecker;
        typedef LengthType_            LengthType;
    
        typedef RET                    FinalListType;
      };
    };
    用户可以这样使用来配置LIST
    ypedef LIST_GENERATOR<int,cp,mono,no_counter,with_tracing>::RET
        TracedIntList;
    

    如果不需要traing

    typedef LIST_GENERATOR<int>::RET IntList;

    最后Shape,Square,Circle用到虚函数,因为我们操作一些列图形几何,需要动态多态。

    而list没有采用虚函数,只是继承类对父类的覆盖,因为对list没有用到动态多态,直接用子类指针。

    另外当前这个程序只是演示GenVoca构架的思想,其实还存在很多问题,比如当前list如果是拷贝构造而来或者owned reference,它的析构函数只能析构一个list的首元素,其它的

    元素无法析构,需要写类外面的一个destory函数,destory(list* l);
     
  • 相关阅读:
    洛谷1280 尼克的任务
    洛谷1140 相似基因
    洛谷1133 教主的花园
    洛谷1130 红牌
    洛谷1122 最大子树和
    洛谷1103 书本整理
    洛谷1077 摆花
    【数学】数学知识习题小结(模板)
    python中的深拷贝和浅拷贝(面试题二)
    python中的深拷贝和浅拷贝(面试题)
  • 原文地址:https://www.cnblogs.com/rocketfan/p/1578153.html
Copyright © 2011-2022 走看看