(转载)Visitor模式---实现家人行为

huangruiguang 2007-09-13 01:15:29
我家有: 老婆, 儿子, 女儿.
我考虑写一个程序模拟她们的生活.
抽象出老婆,儿子和女儿这三个对象,为了易于统一管理和访问这些对象,同时抽象了一些公共基类:Baby.Baby要提供所有可能的接口. 为了把问题简单化,假设老婆主要照顾两个小宝贝和做家务(^-^); 两个小宝贝还小,基本上就是玩.于是我们建立下面的类模型:



根据这个模型,我们可以发现一些不足的地方:

1)抽象接口提供所有子类的行为接口
抽象基类Baby为Wife,Son和Daughter提供了所有的接口,显得比较复杂。
2)子类必须要重写不属于自己的行为
比如儿子比较小,是不参与家务的,但在程序中,Son必须重写Housework(),只是什么都不做。当然,通过某些方式可以避免这问题出现,但同时也会带来其它新问题。
3)增加新的行为比较烦琐
在任何一个类中增加一个新行为,就要在所有的类中做修改。比如,小孩上小学了,老婆不须要照顾小孩了,要上班;同时儿子可能还要踢足球,女儿要课余要学唱歌、舞蹈等。系统不易扩展,增加新功能容易出错;而且会越来越复杂,不易维护。

有必要对设计进行优化,使系统更易扩展和维护。注意以上类结构的特点:Wife、Son、Daughter,这此元素比较稳定;但她们的行为容易变化。
因此我们很自然想到了采用Visitor,建立下面的类模型:

采用Visitor模式重新设计后,基本上消除了以上的不足之处。特别是要增加一个新行为,只要在Visitor层次增加一个新类,不会使系统越来越复杂。下面是针对采用Visitor后的代码实现。
说明:1)代码实现里的Visitor成员函数通过重载机制统一用Visit命名;
2)为编排简单,所有成员函数定义在类声明里实现.

以下是Visitor层次的代码:

struct Visitor
{
virtual void Visit(Wife& wife) = 0;
virtual void Visit(Son& son) = 0;
virtual void Visit(Daughter& daughter) = 0;
};

class BabysatVisitor : public Visitor
{
public:
virtual void Visit(Wife& wife)
{
std::cout << "Wife is taking care of son and daughter.\n";
}

virtual void Visit(Son& son){ }

virtual void Visit(Daughter& daughter){ }
};

HouseworkVisitor也是针对Wife的一个动作,实现和BabysatVisitor类似,略。

class PalyVisitor : public Visitor
{
public:
virtual void Visit(Wife& wife){ }

virtual void Visit(Son& son)
{
std::cout << "Son is playing.\n";
}

virtual void Visit(Daughter& daughter)
{
std::cout << "Daughter is playing.\n";
}
};

以下元素层次的代码:

struct Baby
{
virtual void Accept(Visitor& visitor) = 0;
};

class Wife : public Baby
{
public:
virtual void Accept(Visitor& visitor)
{
visitor.Visit(*this);
}
};

Son和Daughter用同样的方法实现Accept,略.

最后用Family管理她们。

class Family
{
public:

typedef std::multimap<Baby*, Visitor*> BabyMap;

Family()
{
babies_->insert(BabyMap::value_type(new Wife, new WifeVisitor));
babies_->insert(BabyMap::value_type(new Son, new SonVisitor));
babies_->insert(BabyMap::value_type(new Daughter, new DaughterVisitor));
}

void Behave()
{
for (BabyMap::const_iterator it = babies_.begin(); it != babies_.end(); ++it)
it->first->Accept(*it->second);
}
private:
BabyMap babies_;
};

主函数类似:

Family family;

family.Behave();

最后要说明的, 如果经常娶老婆或者经常有小宝宝出生的话,也就说像Wife这些节点容易变化的话, 使用Visitor模式不一定能带来多少好处.

=====================================
不知道如何贴图,在http://hi.baidu.com/huangrg 有完整的文章.
...全文
162 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
SINCE1978 2008-04-11
  • 打赏
  • 举报
回复
建议楼主以后学设计模式不要用这些比喻...我感觉这样去理解设计模式的人和一点不学设计模式的人一样没前途:)

“Visitor模式是可以在不改变Object的前提下增加新的操作”——为什么都这么说?所有visitable实现都得具备语义模糊的accept方法、显得很bad small。虽然我们可以理解这个方法为:接受访问方法,定义这个可访问对象要如何接受访问。
Visitor的致命弱点不是暴露Object的结构,正统做法的具体的访问代码写在:Vistable.accept()一端而不是Vistor.visit()一端,我们自己实现的Vistor其实根本就不用知道Object structure。如果你说的Object的结构是指各个Vistable的具体实现,那么这些实现里公开的基本方法本来就是让外界调用的当然要暴露。


Visitor的致命弱点是有隐晦的自相矛盾,我们使用设计模式的目的是:对修改封闭、对扩展开放。
按照正统做法:用户需要实现的是Vistor那么这个Vistor当然需要做的工作越少越好,所以Vistable.accept()必须实现全部功能,而Vistor.visit()则很薄弱。如果我们要修改访问方式十有八九得改旧有的Vistable.accept()代码、因为访问的方式分散在visit()和accept()两个地方,而不是一厢情愿的只在visit()当中。
而要做扩展比如加入新的Vistable也得照章办事实现accept()还得增加Vistor.visit()。什么工作也不少做。

唯一一点优点可能是使用Visitor可以隐藏访问整个集合的细节。
xingchenbbs 2008-03-19
  • 打赏
  • 举报
回复
星辰技术社区:www.netcsharp.cn ,在这里,您不需要发帖,回帖,甚至是注册,您只需每天浏览下,即可获取最新的.NET技术信息~

我们的宗旨:以最快的速度为您提供最佳的解决方案
manan_ycb 2007-09-29
  • 打赏
  • 举报
回复
这个例子虽然简单,而且对于你的这个模型也适用。

不过楼主需要注意的一点是,你的这个基类Baby是没有数据成员的,这在实际应用中是不可能的,而且如果Wife, Son, Daughter会不断的增加不同的数据的话,会导致你这个系统同样越来越难与维护。

Visitor模式是可以在不改变Object的前提下增加新的操作,但是它的一个致命弱点是必须要暴露Object的结构。

3,408

社区成员

发帖
与我相关
我的任务
社区描述
专题开发/技术/项目 设计模式
社区管理员
  • 设计模式
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧