有时我们会遇到这样的需求,随便举个例子哦
公司的网站有两种语言,英文和中文
现在有个队列存放着对网站的处理操作,比如:
- 导航增加一个Item
- 增加一篇文章
- 推荐位增加一个商品
- …
每个操作都会告诉你是针对英文站还是中文站的,因为即使是相同的操作,针对不同站的做法都是不一样的
如果要设计消息消费者,要怎么设计呢?
如果不懂模式,我应该会这么做:
网站接口:包含所有的处理方法
英文网站(继承网站接口),实现所有的操作
中文网站(继承网站接口),实现所有操作
客户端:接收到消息区分是中文站还是英文站,调用对应实现类的相应方法,可以想象是一个条件语句
这种方式下,如果网站新增了一种操作要怎么改呢,接口要新增一个方法,相应的两个实现类肯定要改,客户端也要改,如果新增了一个泰语站点,也是全部都要改
崩溃了,可以说是一点点都不符合开闭原则,类全被改了
套用访问者模式(简略代码,直接手敲的,不一定符合语法):
被访问者
interface Site(){
public void doSth(Operation visitor);
}
// 英文站
class EnglishSite implements Site{
@override
public void doSth(Operation visitor){
visitor.operate(this);
}
}
// 中文站
class ChineseSite implements Site{
@override
public void doSth(Operation visitor){
visitor.operate(this);
}
}
访问者
interface Operation{
public void operate(EnglishSite enSite);
public void operate(ChineseSite cnSite);
}
// 增加导航栏Item处理类
class AddNavItem implements Operation{
public void operate(EnglishSite enSite){
// 英文站增加导航的操作
}
public void operate(ChineseSite cnSite){
// 中文站增加导航的操作
}
}
// 增加文章处理类
class AddArticle implements Operation{
public void operate(EnglishSite enSite){
// 英文站增加文章的操作
}
public void operate(ChineseSite cnSite){
// 中文站增加文章的操作
}
}
// 增加商品处理类
class AddGood implements Operation{
public void operate(EnglishSite enSite){
// 英文站增加商品的操作
}
public void operate(ChineseSite cnSite){
// 中文站增加商品的操作
}
}
客户端
public void processMsg(Msg msg){
ChineseSite cnSite = new ChineseSite();
EnglishSite enSite = new EnglishSite();
Operation visitor;
switch(操作类型){
// 根据操作类型new出对应的visitor
}
if(英文站点){
enSite.doSth(visitor);
}else{
cnSite.doSth(visitor);
}
}
在这种模式下,如果要新增一个站点,也是令人崩溃的,新增一个被访问者实现类,每一个访问者实现类都要增加对应的方法
但是如果只是新增一个操作呢,我们只要新增一个类,改一下客户端的条件语句即可,改动就少多了
所以再思考一下什么时候才会需要用这种模式呢,首先被访问者要很稳定,比如例子里说的英文站和中文站,一般网站双语足够了,就比较稳定。而被访问者要执行的操作是很不稳定的,经常要增加或删减,如果直接按照面向对象的方法,把对对象的操作全都封装在对象类里面,这种需求下必然导致对象类的频繁修改,使用访问者模式将对象的定义与操作分开,每种操作都是一个访问者Visitor
完结撒花
推荐一个设计模式包教不包会的文档:https://wizardforcel.gitbooks.io/design-pattern-lessons/content/lesson28.html