一、认识访问者模式
1、概念
封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下,定义作用于这些元素的新操作。
如何来理解呢?举个例子来说吧,假如我们都玩过王者荣耀。每个英雄都有三个基本的技能,但是不同的玩家操作英雄技能实现的方式是不一样的。比如说你玩韩信只能送人头,梦泪玩韩信那就是百战百胜。
在这个例子中,庄周和甄姬的三个基本的技能是不变的,但是访问者模式能够在这三个技能之上实现一些不同的效果。我们可以画一张类图进一步去了解它。
2、类图
相信说这种模式比较复杂的都是因为其类图吧,不过我们为每一个模块进行着色之后就能发现其实没那么麻烦。以上类图一共涉及到了六个角色:
(1) Vistor(抽象访问者):为该对象结构中具体元素角色声明一个访问操作接口。就好像是王者荣耀里面不同的玩家。
(2) ConcreteVisitor(具体访问者):每个具体访问者都实现了Vistor中定义的操作。就好比是具体某一个玩家。
(3) Element(抽象元素):定义了一个accept操作,以Visitor作为参数。可以类比成王者里面英雄的模板。
(4) ConcreteElement(具体元素):实现了Element中的accept()方法,调用Vistor的访问方法以便完成对一个元素的操作。可以表示为具体某一个英雄,好比是庄周和甄姬。
(5) ObjectStructure(对象结构):可以是组合模式,也可以是集合;能够枚举它包含的元素;提供一个接口,允许Vistor访问它的元素。也就是庄周和甄姬允许外界访问的元素。
有了这个概念,下面我们就可以使用代码来分析一下了。
二、代码实现
第一步:定义抽象元素(英雄的模板)
public abstract class Hero { //英雄可以接受玩家的访问,让玩家来操作 public abstract void accept(Player visitor); }
第二步:定义具体元素(具体某一个英雄)
首先我们可以定义甄姬
//甄姬 public class ZhenHero extends Hero { //可以接受玩家的操作 @Override public void accept(Player visitor) { visitor.visitZhen(this); } //自身的技能 public void operate() { System.out.println("甄姬放出了技能"); } }
还有一个庄周
//庄周 public class ZhuangHero extends Hero { //接受外部的访问 @Override public void accept(Player visitor) { visitor.visitZhuang(this); } //自身的技能 public void operate() { System.out.println("庄周放出了技能"); } }
第三步:定义抽象访问者(玩家)
//玩家可以访问甄姬和庄周的技能 public interface Player { public abstract void visitZhuang(ZhuangHero element); public abstract void visitZhen(ZhenHero element); }
第四步:定义具体访问者(玩家我和其他玩家)
首先是我自己操作
public class PlayerMe implements Player { @Override public void visitZhuang(ZhuangHero element) { System.out.println("玩家我访问庄周,庄周开始使出技能"); element.operate(); } @Override public void visitZhen(ZhenHero element) { System.out.println("玩家我访问甄姬,甄姬开始使出技能"); element.operate(); } }
然后是其他玩家操作
public class PlayerOthers implements Player { @Override public void visitZhuang(ZhuangHero element) { System.out.println("玩家其他人访问庄周,庄周开始使出技能"); element.operate(); } @Override public void visitZhen(ZhenHero element) { System.out.println("玩家其他人访问甄姬,甄姬开始使出技能"); element.operate(); } }
第五步:定义对象结构
public class ObjectStructure { //保存所有需要被访问的元素 private List<Hero> heros = new ArrayList<Hero>(); public void handleRequest(Player visitor) { //访问所有元素 for(Hero hero : heros) { hero.accept(visitor); } } public void addHero(Hero hero) { heros.add(hero); } }
第六步:客户端测试一下
public class Client { public static void main(String[] args) { ObjectStructure os = new ObjectStructure(); Hero zhuang = new ZhuangHero(); Hero zhen = new ZhenHero(); os.addHero(zhuang); os.addHero(zhen); Player visitorMe = new PlayerMe(); Player visitorOthers = new PlayerOthers(); // 让访问者访问对象结构中的元素 os.handleRequest(visitorMe); os.handleRequest(visitorOthers); } }
最后一步我们就能看到结果了
这就是访问者模式。
三、分析访问者模式
访问者模式使用的条件在于对象的结构一般不宜发生改变,但是操作缺不一样的情况。比如复杂的集合对象、XML文档解析、编译器的设计等就常常会用到这个模式。
优点在于访问者模式解决的问题,也就是使用场景,缺点就是不使用对象结构宜发生改变的情况。