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
是一個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.
- 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即可,然後修改相應操作添加過程列印的資訊。
List : TracedList[OptCounterList] | OptCounterListOptCounterList : LengthList[BasicList] | BasicListBasicList : 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對於使用者應該是透明的。
使用者可能會設定出使用MonomorphicCopier 和 EmptyDestroyer這樣會帶來記憶體流失的錯誤配置。
這裡面應該多一層抽象層,隔離開來。使用者只要聲明我用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);