Visitor Pattern
封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作,主要是将数据结构与数据操作分离,解决数据结构和操作耦合性问题;
基本工作原理:在被访问的类里面加一个对外提供接待访问者的接口;
结构
Visitor抽象访问类:为该对象结构中的每一个类声明一个visit操作;
ConcreteVisitor具体的访问类:实现每个有visitor声明的操作,是每个操作的实现部分;
ObjectStructure数据结构类:能枚举它的元素,可以提供一个高层的接口,用来允许访问者访问元素;
Element抽象接收类:定义一个accept方法,接收一个访问者对象;
ConcereteElement具体接收类:为具体元素实现了accept方法;
实例代码
抽象访问类:
public abstract class Action {
private String type;
public String getType() {
return type;
}
public Action(String type) {
this.type = type;
}
//得到男性 的测评
public abstract void getManResult(Man man);
//得到女的 测评
public abstract void getWomanResult(Woman woman);
}
具体实现访问类:
public class Success extends Action {
public Success(String type) {
super(type);
}
@Override
public void getManResult(Man man) {
// TODO Auto-generated method stub
System.out.println(man.getName()+"——赞成票");
}
@Override
public void getWomanResult(Woman woman) {
// TODO Auto-generated method stub
System.out.println(woman.getName()+"——赞成票");
}
}
public class Fail extends Action {
public Fail(String type) {
super(type);
}
@Override
public void getManResult(Man man) {
// TODO Auto-generated method stub
System.out.println(man.getName()+"——反对票");
}
@Override
public void getWomanResult(Woman woman) {
// TODO Auto-generated method stub
System.out.println(woman.getName()+"——反对票");
}
}
抽象接收类:
public abstract class Person {
private String name;
private String act;
public Person(String name) {
this.name = name;
}
public String getAct() {
return act;
}
public void setAct(String act) {
this.act = act;
}
public String getName() {
return name;
}
//提供一个方法,让访问者可以访问
public abstract void accept(Action action);
}
具体实现接收类:
public class Man extends Person {
public Man(String name) {
super(name);
}
@Override
public void accept(Action action) {
// TODO Auto-generated method stub
action.getManResult(this);
this.setAct(action.getType());
}
}
//说明
//1. 这里我们使用到了双分派, 即首先在客户端程序中,将具体状态作为参数传递Woman中(第一次分派)
//2. 然后Woman 类调用作为参数的 "具体方法" 中方法getWomanResult, 同时将自己(this)作为参数
// 传入,完成第二次的分派
public class Woman extends Person{
public Woman(String name) {
super(name);
}
@Override
public void accept(Action action) {
// TODO Auto-generated method stub
action.getWomanResult(this);
this.setAct(action.getType());
}
}
数据结构类:
//数据结构,管理很多人(Man , Woman)
public class ObjectStructure {
//维护了一个集合
private List<Person> persons = new LinkedList<>();
//增加到list
public void attachSuc(Person p) {
p.accept(new Success("成功"));
persons.add(p);
}
public void attachFail(Person p){
p.accept(new Fail("失败"));
persons.add(p);
}
//移除
public void detach(Person p) {
persons.remove(p);
}
//显示测评情况
public void display() {
for(Person p: persons) {
System.out.println(p.getName()+"——"+p.getAct());
}
}
}
测试类:
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
ObjectStructure objectStructure = new ObjectStructure();
System.out.println("------开始投票--------");
objectStructure.attachSuc(new Man("男1"));
objectStructure.attachSuc(new Woman("女1"));
objectStructure.attachFail(new Man("男2"));
objectStructure.attachFail(new Woman("女2"));
System.out.println("-----投票结果统计-------");
objectStructure.display();
}
}
实现结果:
优缺点
优点
1、访问者模式符合单一职责原则、让程序具有优秀的扩展性、灵活性非常高 ;
2、访问者模式可以对功能进行统一,可以做报表、UI、拦截器与过滤器,适用于数据结构相对稳定的系统;
缺点
1、具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的,这样造 成了具体元素变更比较困难 ;
2、违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素 ;
3、因此,如果一个系统有比较稳定的数据结构,又有经常变化的功能需求,那么访问者模式就是比较合适的 ;