我也设计模式——25.Visitor 上

1)现实中,如果我家的电脑坏了,我就去找电脑维修工来你家来修,这个人会在知道我家这个对象,然后来我家让电脑重装系统;当然若你家的电脑坏了,也会找这个维修工来修理,但可能是换硬盘。这就是访问者模式。电脑维修工是ConcreteVisitorA,你家是ConcreteElementA。UML图如下:
    

怎么在客户端使用呢?

            电脑维修工 v1 = new 电脑维修工();
            家庭 e 
= new 我家();
            e.要求维修电脑(v1);

从而维持了一个“双重分派”——我家 在 要求维修电脑() 这个方法中,把 自己(this) 这个对象传给了 电脑维修工;而电脑维修工根据我家找到相应的重载方法Do,在这个方法中,执行 我家.电脑重装系统()。于是,便完成双发交互操作,都将自身暴露给对方。注意,彼此暴露互相身份,正是Visitor模式的缺点:对象间藕合性大了,怎么讲呢,就是浦志高叛变了,会把他知道的江姐也出卖的。

2)如果我家很不幸,房子漏水,那么我又要找房屋维修工来修屋顶,我家这个对象就要暴露给这个房屋维修工。于是添加一种维修工:


 

相应在Client这么使用:

            房屋维修工 v2 = new 房屋维修工();
            家庭 e 
= new 我家();
            e.要求维修房屋(v2);

3)可以看出,对于某个家庭,增加一个需求(如修理屋顶),只需要在自身中增加这个需求方法 要求屋顶维修(),然后维修工中增加一个新的维修工种类——房屋维修工,就可以了。当然,只是我家增加 要求屋顶维修()就可以了, 其他家(如你家)是不一定需要的,于是在房屋维修工相应的重载Do方法中,不做任何事情就可以了。

public void Do(你家 you)
{
    
//不做任何事情
}

也就是说,增加新的需求很容易,一个成熟住宅小区都是这样子的。
但是,如果增加一个新家庭,就是说,多了一个 小强家,那么,所有的维修工(包括基类“维修工人”)的都应增加对应这一新家庭的操作,这是非常非常麻烦的——不符合开闭原则。这时候小区应该有一个Mediator,负责执行命令,这是中介者模式+命令模式在成熟小区对于新家庭的便利之处。

越写越不像人话了,我不知道读者到这里还会有多少人会明白,以上都是今天下午和Will & Tiger讨论的精华。
这一节的下部,我会介绍:
开闭原则,
GOF中的访问者UML图,
Visitor和Command的区别,
弱类型集合的操作,
Visitor的优缺点,
Visitor的使用场合。

posted @ 2007-04-17 22:14  包建强  Views(793)  Comments(2Edit  收藏  举报