分享
 
 
 

对话:#05 通过任何其他名字

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

[声明]:本英文资料源自于Herb Sutter 创建的“Conversation”栏目,“C++ 翻译小组”的翻译作品供学习交流与参考用途,不得用于任何商业用途。未经Herb Sutter、Jim Hyslop同意,不得转载;对于违反以上条款,翻译小组对此不负任何责任;特此声明。

文章来源:http://www.gotw.ca

版权归属:Herb Sutter and Jim Hyslop

译 者:morningsing(CSDN)

对话:#05 通过任何其他名字

悬在几乎一百公里以外的天空,那个小小的行星占据了观察孔视野相当大的部分。它的表面看起来好像玻璃碎裂后又用冰冻的胶水修补过。许多冻结的河流蜿蜒在十字形的低矮山脉之间。荒凉的木卫二是那样的美轮美奂。

扬声器传出“上船,第三和第七区”,然后又恢复沉默。

珍妮和我在观察口边上和一群专家挤作一团,我们中的大多数看起来像是瞠目结舌的年轻宇航员。可我们不在乎。当然,在飞船中的任何地方都可以看到更好的景色,但当看到真实、原原本本的光直接从月球反射进你的眼睛时,总能有一丝特殊的感觉。

“真是个好地方,” 珍妮自告奋勇的说。“他们将消息封锁得紧紧的,现在也还这样。”

“紧紧的?他们应该告诉我们真正的目的地。”

“不会。我相信我们会很快找出他们在冰层底下发现了什么。”

“嗯?嗯。”我回答,“仅仅来到这里,我就很高兴。当我以前看到这里的图片,还以为是处理过的幻境,没想到真的这么美——不,比图片更美。我们真的来到这里了。这使我想起自己的第一份工作。”

她开玩笑地哼了一声。“任何东西都会使你想起第一份工作。”

“我还年轻,所以容易受到感染。无论如何,刚才关于这次旅行的谈论又使我想起了它。”

“啊。”她停顿了一下。“你到底想说什么?”

我笑了,接下去解释……

- - - - - - - - - - - - - - - - - - - - - - - - -

我曾经为一个设计问题苦苦挣扎。我真的希望自己解决,因为见习期即将结束,我希望证明自己。

你记得毕业后的第一份工作,对吧?正确地处理事情是多么的重要。我一直记得新进公司的同事们,因为无法与Guru打好交道而没有通过见习。别误解我的意思,她是一个优秀的程序员,只是有一点儿……古怪。现在她是我的良师益友,我非常希望在她面前证明自己。

我需要在类体系中加入一个新的虚函数,但其他团队维护着类体系并且不允许别人改动。这个类体系看起来像是这样: class Personnel

{

public:

virtual void Pay ( /*...*/ ) = 0;

virtual void Promote( /*...*/ ) = 0;

virtual void Accept ( PersonnelV& ) = 0;

// … 其他函数 …

};

class Officer : public Personnel {{ /* 改写虚拟函数 */ };

class Captain : public Officer { /* 改写虚拟函数 */ };

class First : public Officer { /* 改写虚拟函数 */ };

我需要一个函数在对象是Captain和First军官时拥有不同的行为。虚拟函数恰好合适,在Personnel或Officer中声明,在Captain和First中改写。

麻烦是:我不能加入新的函数。我知道仅仅加入使用运行时类型信息的类型检查就可以解决问题,像这样: void f( Officer &o )

{

if( dynamic_cast<Captain*>(&o) )

/* do one thing *//* 某些操作 */

else if( dynamic_cast<First*>(&o) )

/* do another thing *//* 某些操作 */

}

int main()

{

Captain k;

First s;

f( k );

f( s );

}

但我知道这种类型检查是不符合公司的编程规范的。“我不喜欢这样,”我对自己,也对别人这样说:“但这一次,我觉得有充足的理由让他们更改这个规范。很显然,没别的方法可以解决问题啊。”

“所有的问题都可以通过多加一个间接层来解决。”

我吓了一跳,Guru在我身后说话呢!“什么?”我转向她问。

“所有的问——”

“哦,是的。”我禁不住打断她。“我听见了你所说的,我只是不知道您从哪儿来的。”老天!我想这是一种掩饰,不过部门里的大半同事都会这么做的。

“啊,不过你会的。”Guru把身体探向我说:“你会知道的,我年轻的徒弟。”她专注地盯了我一会儿,然后直起身子。“我的孩子,C的信徒经常使用基于对象类型的分支语句来引导程序流。考虑这个比喻。”她拿起一支干擦笔: /* 一个典型的C程序 */

void f(struct someStruct *s)

{

switch(s->type) {

case APPLE:

/* 进行某些操作 */

break;

case ORANGE:

/* 进行某些其他操作 */

break;

/* 等等 */

}

}

“当这些信徒向先知Stroustrup学习时,”她继续说,“也就是说学习C++时,他们必须学习如何设计好的类体系。”

“是的,”我再次打断,渴望表现出自己确实懂一些东西,“他们应该创建一个以Fruit为基类的类体系,然后派生Apple和Orange。这不错吧?派生类中应该使用虚拟函数。”

“很好,我的孩子。C++的信徒经常借用这个比喻指出switch语句烦琐,容易滋生错误,劝说C的执迷者改投C++的怀抱。。然而从另一种角度看待这个比喻:通过引进一个虚拟函数,你就加入了一个间接层。”她放下笔,“你所需要的是一个新的虚拟函数。”

“啊哈,很对。我知道,”我炫耀地总结道:“而且我现在无法这样做。”

她点点头。“因为你不能修改类体系。是的。”

这使我迟疑了一下,但仅仅是一瞬间。“哦,你知道我们无法改变它?那么你明白了。”

“哦,是的。是我设计了类体系。”

“哦。”这使我彻底住了嘴。

“因为非同寻常的系统间交叉依赖,这个体系较之一般情况必须更加稳定,但允许你加入虚函数来避免类型分支(type-switching)代码。你可以通过加入新的间接层来解决问题。再次考虑那个比喻。 Personnel:: Accept是做什么的?”

“呃,嗯?”我如坠雾中。

“这个类实施的是Poorly Named模式,或者说PNP。也被称作Visitor模式[1]。”

“呃,嗯。”我现在明白了一些。“我曾经读到过Visitor模式。但那只是针对能够互相迭代访问的对象,不是么?”

她叹了口气。“一个常见的误解。考虑一下V的含义,不是Visitor而是Virtual。”她解释道,“PNP最有用的地方,就是在不会进一步改变类体系的情况下增加虚拟函数。首先注意Accept在Personnel类和子类中是如何实现的。”她摘出如下代码: 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会以正确派生类型调用,而且重载解析过程会选出正确地函数。这就像加入了一个新的虚函数,是么?”

“的确是的,我的孩子。新加入的函数通常只需占用客户类的公共接口,但在其他任何方面都像虚函数一样,即使它并非成员函数。所需的一切只是初始类体系支持Accept,以使自己能够扩展。如果将来我们发现经常用新的子类扩展Personnel体系,或者希望更好地管理编译依赖,可以移植到Acyclic Visitor——除了稍许修改Accept函数,完全不必改变Personnel及其基类。[2, 3]

我明白了。“OK,那我可以这样做。”我飞快的写道: 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();

}

Guru专心地盯着我的代码。“这些代码是为什么系统写的?”

“啊……是个模拟器。”

“我知道了。好的,继续吧,孩子。写剩下的吧。”

我增加了一个测试例程: void f( Personnel& p )

{

p.Accept( DoSomething() ); // like 类似 p.DoSomething()

}

int main()

{

Captain k;

First s;

f( k );

f( s );

}

Guru踱步离去,一边压了压耳后一络灰白的头发:“很好。确实,这个函数没有直接将原先的类体系局限于personnel::作用域。但在这时,这个函数不管使用任何名字都是虚拟的。”她笑着走开。她的声音随着身影慢慢消失。“Visitor模式即使采用了别的名字也一样有用,而且更容易描述。不过事情总是这样的……”

- - - - - - - - - - - - - - - - - - - - - - - - -

随着飞船的旋转,巨大的木星——它的壮美使木卫二表面相形见绌——渐渐进入了观察孔的视野。

“我将申请使用一会儿着陆服,”我决定:“能在这样的天空下走走该多好啊。即使我们只是旅行者。”

“我们是旅行者。”珍妮赞成道:“不过我想知道我们是不是第一批到达的?”

于是,一段时间里,我们只是默默的望着天空。

[注释]

[1] E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley, 1995).

[2] R.C. Martin. "Design Patterns for Dealing with Dual Inheritance Hierarchies," C++ Report, April 1997). Available online at http://www.objectmentor.com/publications/dih.pdf.

[3] R.C. Martin, "Acyclic Visitor," in R.C. Martin, D. Riehle, F. Buschmann (eds.), Pattern Languages of Program Design 3 (Addison-Wesley, 1998). Available online at http://www.objectmentor.com/publications/acv.pdf.

[关于作者]

Herb Sutter

是个独立顾问,也是ISO/ANSI C++标准委员会的秘书。你可通过hsutter@acm.org.联系他

Jim Hyslop

Leitch Technology International Inc.资深的软件设计师,你可通过jim.hyslop@leitch.com联系他

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有