与大虾对话: 领悟设计模式(3)

2008-04-09 04:29:05来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折


“您终于了解了情况,我们没法动它。也不知道这个该死的类层次是哪个家伙设计的...” 我嘀嘀咕咕着。

“是我设计的。”

“啊...,真的?!这个,嘿嘿...”,我极为尴尬。

“这个类层次必须非常稳定,因为有跨平台的问题。但是它的设计允许你增加新的virtual function,而不必烦劳RTTI。你可以通过增加一个间接层次的办法解决这个问题。请问,Personnel::Accept是什么?”

”嗯,这个...”

“这个类实现了一个模式,可惜这个模式的名字起得不太好,是个PNP,叫Visitor模式。”

[译者注:PNP,Poor-Named Pattern, 没起好名字的模式]

“啊,我刚刚读过Visitor模式。但是那只不过是允许若干对象之间相互迭代访问的模式,不是吗?”

她叹了一口气,“这是流行的错误理解。那个V,我觉得毋宁说是Visitor,还不如说是Virtual更好。这个PNP最重要的用途是允许在不改变类层次的前提下,向已经存在的类层次中增加新的虚函数。首先来看看Personnel及其派生类的Accept实现细节。”她拿起笔写下:

void Personnel::Accept( PersonnelV& v )
{ v.Visit( *this ); }

void Officer::Accept ( PersonnelV& v )
{ v.Visit( *this ); }

void Captain::Accept ( PersonnelV& v )
{ v.Visit( *this ); }

void First::Accept ( PersonnelV& v )
{ v.Visit( *this ); }
“Visitor的基类如下:”

class PersonnelV/*isitor*/
{
public:
virtual void Visit( Personnel& ) = 0;
virtual void Visit( Officer& ) = 0;
virtual void Visit( Captain& ) = 0;
virtual void Visit( First& ) = 0;
};
“啊,我记起来了。当我要利用Personnel类层次的多态性时,我只要调用Personnel::Accept(myVisitorObject)。由于Accept是虚函数,我的myVisitorObject.Visit()会针对正确的对象类型调用,根据重载法则,编译器会挑选最贴切的那个Visit来调用。这不相当于增加了一个新的虚拟函数了吗?”

“没错,小菜鸟。只要类层次支持Accept,我们就可以在不改动类层次的情况下增加新的虚函数了。”

“好了,我现在知道该怎么办了”,我写道:

class DoSomething : public PersonnelV
{
public:
virtual void Visit( Personnel& );
virtual void Visit( Officer& );
virtual void Visit( Captain& );
virtual void Visit( First& );
};

void DoSomething::Visit( Captain& c )
{
if( femaleGuestStarIsPresent )
c.TurnOnCharm();
else
c.StartFight();
}

void DoSomething::Visit( First& f )
{
f.RaiseEyebrowAtCaptainsBehavior();
}
void f( Personnel& p )
{
p.Accept( DoSomething() ); // 相当于 p.DoSomething()
}

int main()
{
Captain k;
First s;

f( k );
f( s );
}
大虾满意地笑了,“也许这个模式换一个名字会更好理解,可惜世事往往不遂人意...”。

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:一个画渐变的方法

下一篇:2002-01-08 Borland宣布Borland Enterprise Studio for Windows