分享
 
 
 

Visitor Pattern Introduction

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

Visitor Pattern Introduction

(wang hailong)

Visitor Pattern可能是设计模式中最复杂的模式了。Visitor Pattern从Double Dispatch Pattern派生而来,由Double一词可见其复杂度。

Visitor Pattern,顾名思义,有访问者和被访问者,既然,以访问者命名,那么,主要的工作都是访问者来做。

本文不从程序设计入手,而从一个日常生产生活的例子入手,来解释Visitor Pattern。

一个生产高能电池的厂家,下设一个客户服务部门,其主要任务之一就是收集用户的反馈意见,以便改进产品功能和服务质量。

以前,客户服务部门只是采用发放调查问卷的方式。调查问卷的问题千篇一律,不能针对特殊用户的兴趣点,尤其一些集体用户,不会认真对待这些问卷,懒得把问卷发到具体的使用者手里,而且,很多用户不愿意花时间把调查问卷寄回。调查结果不全面,不真实,几乎没有任何效果。

之后,个性化服务、CRM客户关系管理等概念兴起,客户服务部门引入了一套CRM客户(用户)关系管理系统,对客户信息进行管理。针对不同用户的特点,采用不同的调查方式。采用电话、E-Mail、传真、问卷、登门拜访等多种方式,对用户进行调查访问。针对一些集体用户,比如,企事业单位用户,客户服务人员首先访问联系该单位集体,安排好时间之后,客户服务人员具体访问每一个具体用户,这些用户接受客户服务人员的访问,给出亲身使用电池产品的第一手资料。

还有的情况,集体单位下面还有子单位,比如,公司下面有子公司。那么,遵循同样的流程,分别访问下面的子公司,这些子公司接受客户服务人员的访问,安排好时间之后,客户服务人员具体访问每一个具体用户,这些用户接受客户服务人员的访问,给出亲身使用电池产品的第一手资料。

我们可以看到,这是一个典型的Visitor Pattern。客户服务部门就是Visitor,不同类型的用户就是被访问者。客户服务部门(Visitor)几乎做了所有的工作,尽量不给用户增加负担。

下面给出这个例子的示意代码。

// 客户服务部门类,

// 总结CRM客户关系管理系统的客户类型信息,定义以下的方法

class ServiceDepartment{

// Email访问方式

private Email sendEmail(…){

}

// 电话访问方式

private Answer callPhone(…){

}

// 访问用户。

// 这是ServiceDepartment类的入口点方法。

// 注意,参照下面的User的定义代码,User是一个接口类型

public void visitUser(User aUser){

user.accept(this);

}

// 访问习惯Email访问的用户

public void visitEmailUser (EmailUseranEmailUser){

// send email to email user

Email reply = anEmailUser.replyEmail( this.sendEmail() );

// put anwer to database

}

// 访问习惯电话访问的用户

public void visitPhoneUser (PhoneUseraPhoneUser){

// call phone user

Answer answer = A.answerPhone( this. callPhone () );

// put answer to database

}

// 访问公司用户

public void visitCompanyUser( CompanyUser companyUser){

// visit company user

List userList = companyUser.getUserList();

for each user in userList{

// 访问每个用户,每个用户都接受访问。

Visitor.visitUser(user);

// 注意,这里User的类型有可能是CompanyUser类型。

// 这时形成对子公司用户的递归调用。

}

}

}

// 以下列出每个用户类的代码,

// 因为用户是被访问者,负担很少。所以,每个用户的方法都很简单。

// 公共接口类,每个用户类都应该实现这个接口。

public interface User{

// 接受客户服务部门的访问

public void accept(ServiceDepartment visitor);

};

// Email user 类

public class EmailUser implements User {

// 用Email反馈

public Email replayEmail(Email question){

}

// 接受客户服务部门的访问

public void accept(ServiceDepartment visitor){

visitor.visitEmailUser(this);

}

};

// Phone user 类

public class PhoneUser implements User{

// 接听电话,进行反馈

public Answer answerPhone(Phone question){

}

// 接受客户服务部门的访问

public void accept(ServiceDepartment visitor){

visitor.visitPhoneUser(this);

}

};

// company user 类

public class CompanyUser implements User {

// 接受客户服务部门的访问

public void accept(ServiceDepartment visitor){

visitor.visitCompanyUser(this);

}

};

下面给出一个使用上述模式的例子。

public class TestMain{

public void main(String[] args){

// create a visitor

ServiceDepartmant visitor = new ServiceDepartmant();

// 从数据库中取得所有的用户信息

// 这些用户的类型,有可能是PhoneUser, EmailUser,还有可能是CompanyUser。

for each user created from database {

// 访问每一个用户,用户接受访问,给出反馈,存放到数据库中

visitor.visitUser(user);

}

}

}

好了,所有的示意代码都在这里了。现在,我们考虑问题的变化和扩展。毕竟,设计模式的目的就是为了让变化的部分越小越好,越简单越好。

客户服务部门引入CRM客户关系管理系统,就是为了更好地对应客户(用户)信息的变化。

过了一段时间,CRM客户关系管理系统加入了一个新用户的信息,这个用户习惯使用传真回答调查问卷。这时,我们多了一个用户类,FaxUser。我们需要对上述的ServiceDepartment类(visitor类)进行扩展。

第一种方法是,直接修改ServiceDepartment类,增加一个visitFaxUser(FaxUser)方法。这种方法比较直观,但是需要修改以前的代码。

public class ServiceDepartment{

… // 以前的代码

// 增加一个新的方法,发送传真

private Fax sendFax(…){

}

// 增加一个新的方法,访问习惯传真的用户

void visitFaxUser(FaxUser aFaxUser){

Fax fax = aFaxUser.replyFax(this.sendFax());

// 把fax的信息存放到数据库

}

};

这时,新增的FaxUser的代码如下:

public class FaxUser implements User{

// 用传真反馈

public Fax replyFax(Fax fax){

}

// 接受客户服务部门的访问

public void accept(ServiceDepartment visitor){

visitor.visitFaxUser(this);

}

}

第二种方法是,继承ServiceDepartment类,定义一个新类ExtendedServiceDepartment,增加一个visitFaxUser(FaxUser)方法。这种方法的好处是不用修改以前的代码,但是,新增加的User类,需要知道新类ExtendedServiceDepartment的定义。

下面给出示意代码,ExtendedServiceDepartment类。

public class ExtendedServiceDepartment extends ServiceDepartment{

// 增加一个新的方法,发送传真

private Fax sendFax(…){

}

// 增加一个新的方法,访问习惯传真的用户

void visitFaxUser(FaxUser aFaxUser){

Fax fax = aFaxUser.replyFax(this.sendFax());

// 把fax的信息存放到数据库

}

};

这时,新增的FaxUser的代码如下:

public class FaxUser implements User{

// 用传真反馈

public Fax replyFax(Fax fax){

}

// 接受客户服务部门的访问

public void accept(ExtendedServiceDepartment visitor){

visitor.visitFaxUser(this);

}

}

后记 为什么写这篇文章?

以前看到一本书,讲述TCP/IP编程。作者解释Socket的时候举了一个接听电话的例子,讲述的很明白。

1.你要接听电话,首先你要有一个电话,所以,第一步,create a Socket. 这里,Socket就是你的电话。

2.你还要有一个电话号码,对于你的Socket来说,你的IP地址和端口号就是电话号码,所以,第二步,bind to a port.

3.你还要等在电话旁边,等电话铃响,listen to the port.

4.别人要给你打电话,他(她)也要有一个电话,他需要create a Socket。

5.他需要拨打你的电话号码,connect to your IP address and port.

6.他的电话来了,你要接听他的电话,accept his connection。这时,还有来电显示,你知道他的电话号码(IP地址)。

7.你同时能接听几个打来的电话,你和他们开始通话。read and write.

8.通话结束,你说,“你先挂电话吧,我还要和别人讲话。”他把电话挂了,close his Socket。

看了这段之后,我很受启发。后来写了一篇文章《Design Pattern Introduction》,提到Observer Pattern,举了邮件订阅,手机短信订阅的例子。

Visitor Pattern,是一个比较复杂的设计模式。有很多关于Visitor Pattern的争论,有些人建议使用,有些人建议不使用。这里,我多费些笔墨,把Visitor Pattern作为一个日常生产生活的场景描述出来。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
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- 王朝網路 版權所有