访问者模式
实现思路:向对象结构类中添加元素,然后定义多种访问者,使用对象结构类去接受访问者即可。
六个角色:
- 抽象访问者(Visitor):抽象出访问元素的动作,该操作接口的名字和参数标识了发送访问请求给具体访问者的具体元素角色,这样访问者就可以通过元素角色给具体访问的具体元素角色。这样访问者就可以通过该元素角色的特定接口直接访问它
- 具体访问者(ConcreteVisitor):实现访问元素的动作,实现每个由访问者Visitor声明的操作
- 抽象元素(Element):定义一个接受访问的操作(Accept操作),其参数为访问者
- 具体元素(ConcreteElement):实现抽象元素角色提供的Accept操作
- 对象结构类(ObjectStructure):可以枚举元素,并且管理元素,这是使用访问者模式必备的角色,它要具备以下特征,能枚举它的元素,可以提供一个高层的接口以允许该访问者访问它的元素,可以是一个复合(组合模式)或是一个集合。如一个列表或一个无序集合。
- 客户端(Client) :定义元素集合,然后接受不同访问者的访问
结构图:
撇开现象看本质
Visitor.visit(Element element){}
Element.accept(Visitor visitor){
visitor.visit();
}
看到这 visitor 和 accept 方法我们立刻明白了,原来是重点是回调函数
应用场景:用户去访问博客
分析:用户可以通过电脑上的Web方式(访问者)或者手机Wap方式(访问者)或者Pad平板(访问者)的方式去访问博客,每篇博客是一个元素(有A博客,B博客,C博客),然后博客列表是一个对象结构类。下面我们在控制台程序去演示一下如何使用Visitor Pattern:
public interface Visitor { public void visit(Element element); } // 网页版访问 class WebVisitor implements Visitor { @Override public void visit(Element element) { System.out.println("Web用户浏览blog"); } } // 手机版访问 class PhoneVisitor implements Visitor { @Override public void visit(Element element) { System.out.println("手机用户访问blog"); } } //平板访问 class PadVisitor implements Visitor { @Override public void visit(Element element) { System.out.println("平板用户访问blog"); } }
文章Blog类
public abstract class Element { private String name ; public Element(String name) { this.name = name; } abstract public void accept(Visitor visitor); public String getName() { return name; } public void setName(String name) { this.name = name; } } class BlogElementA extends Element { public BlogElementA(String name) { super(name); } @Override public void accept(Visitor visitor) { System.out.println(this.getName()+"_A被访问"); visitor.visit(this); } } class BlogElementB extends Element{ public BlogElementB(String name) { super(name); } @Override public void accept(Visitor visitor) { System.out.println(this.getName()+"_B被访问"); visitor.visit(this); } } class BlogElementC extends Element{ public BlogElementC(String name) { super(name); } @Override public void accept(Visitor visitor) { System.out.println(this.getName()+"_C被访问"); visitor.visit(this); } }
Context 环境角色 对象结构类(ObjectStructure)
public class Context { private List<Element> blogList = new ArrayList<>(); public void add(Element element) { blogList.add(element); } public void remove(Element element) { blogList.remove(element); } public void accept(Visitor visitor) { for(Element element:blogList){ element.accept(visitor); } } } public class Client { private static Context ctx = new Context(); public static void main(String[] args) { ctx.add(new BlogElementA("我的家乡(抒情散文)")); ctx.add(new BlogElementB("访问者模式(技术指导)")); ctx.add(new BlogElementC("旅行指导(建议)")); ctx.accept(new WebVisitor()); ctx.accept(new PadVisitor()); ctx.accept(new PhoneVisitor()); } }
运行结果
我的家乡(抒情散文)_A被访问:来自Web用户浏览blog 访问者模式(技术指导)_B被访问:来自Web用户浏览blog 旅行指导(建议)_C被访问:来自Web用户浏览blog 我的家乡(抒情散文)_A被访问:来自平板用户访问blog 访问者模式(技术指导)_B被访问:来自平板用户访问blog 旅行指导(建议)_C被访问:来自平板用户访问blog 我的家乡(抒情散文)_A被访问:来自手机用户访问blog 访问者模式(技术指导)_B被访问:来自手机用户访问blog 旅行指导(建议)_C被访问:来自手机用户访问blog
对于某个对象或者一组对象,不同的访问者,产生的结果不同,执行操作也不同。此时,就是访问者模式的典型应用了。
应用场景
1 不同的子类,依赖于不同的其他对象
2 需要对一组对象,进行许多不相关的操作,又不想在类中是现在这些方法
3 定义的类很少改变,但是执行的操作却经常发生改变。