|
基于策略的类设计(Policy)
设计的类准则就是要进行复用,但是面向对象却把类作为最小的单位,这样造成复用的困难,或者根本无法复用。请看下面的例子:
class A
{
public:
void kao() { }
};
class B
{
public:
void kao() { }
void dao() { }
};
如果我要写一个C,他需要A的kao()的实现和B的dao()的实现,那么我们就陷入一个困难的情景,难道我们从A和B继承?这将把A和B的其他不相关的东西都通通弄进来。不然我们只要拷贝代码?这是完全不对的。只有一种解法,就是把这个函数提出来,作为一个模板函数,象这样:
template<class T>
void kao(T* p) { }
template<class T>
void dao(T* p) { }
但是我们发现如果kao()和dao()需要访问T的私有成员的时候,我们又遇到困难,而且我们并没有直观的指出:kao()和dao()是A,B的一部分,这将造成规则(也就是要求我们记忆的东西)。
我们希望在我们实现A,B的时候就明确自己在干什么,也明确A,B里到底有什么。所以我们用下面的方法:
class K
{
public:
void kao() { }
};
class D
{
public:
void dao() { }
};
class A : public K { };
class B : public D
{
public:
void kao() { }
};
class C : public K, public D { };
我们称K,D为策略,类有策略组成,这些策略就是方面。
当然,找到完全正交的策略是非常好的,就象上面的B一样,他同时使用了kao(),dao(),这个时候如果K和D是互不相关的,那么很好,但是事情却经常不是这样,如果我们有一个精灵类,他包括动画管理和图形显示,而我们可以有好几种动画管理策略和图形显示策略,这个时候我们就可以任意组合,但是,动画策略很可能需要调用画图函数,这个时候因为我们的动画策略和显示策略是分开的,所以动画策略看不到显示策略提供的函数,这个时候一般需要使用接口,但是这个会生成大量接口,你需要为你每一个功能实现接口。但是我们提供了一种不正交的策略的实现方法,他的基础是模板的提前扫描,迭代编译,迟后联接。
请看:
template<class T>
class K
{
public:
void kao() { static_case<T*>(this)->dao(); }
};
template<class T>
class D
{
public:
void dao() { static_cat<T*>(this)->kao(); }
};
template< template<class> class T1, template<class> class T2>
class B_Impl : public T1<B_Impl>, public T2<B_Impl> { };
typedef B_Impl<K, D> B;
为了方便,我实现下面的策略
template<class T>
class Relex
{
private:
Relex(const Relex&);
Relex& operator = (const Relex&);
public:
typedef T _HostType;
typedef T& _HostReference;
typedef T* _HostPointer;
public:
Relex() { }
T* GetHostPtr() { return reinterpret_cast<T*>(this); }
};
则上面的K,D 可以改写为:
template<class T>
class K : private Relex<T>
{
public:
void kao() { GetHostPtr()->dao(); }
};
template<class T>
class D : private Relex<T>
{
public:
void dao() { GetHostPtr()->kao(); }
};
类的组合实现是非常重要的复用机制,他是将来的编程的发展方向,随着编译器的标准化,使用模板已不再是障碍。
|
|