概念
访问者模式:表示一个作用于某个对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作
介绍
访问者模式的概念非常不容易理解,用通俗的话说,我希望在满足“开放-封闭原则”的条件下,能改变元素的操作。访问者模式本来就很复杂,再加上使用上还有条件,所有实际工作中也很少能用到,下面我们直接看例子吧。
我们需要设计一个程序,满足下面要求:
- 程序能反应“男人”、“女人”在不同的状态下的不同反应。
- 状态分为:成功、失败、恋爱。
- 状态可能在后期会有新增,新增状态不会影响原先的代码。
- “男人”、“女人”的类别后期不会增加,是一个稳定的类别。
那么UML如下
UML图
- 我们将男人和女人认为是稳定的类别,也就是后期不会怎么修改的类别
- 状态是我们需要考虑的随时可能修改的
- 对象类结构:我们使用对象类结构来对比“男人”和“女人”的不同
双分派技术
上面使用到了双分派思想,可能概念比较难懂,建议直接看代码,再回来看概念:
根据字面意思就是进行了2次对类别进行分派:
- 第一次分派:客户端将具体的状态作为参数传递给“男人”,完成第一次分派。
- 第二次分派:“男人”将自己作为参数,传递给状态。
双分派意味着得到执行的操作由“人”和“状态”共同决定
代码
- Person 抽象类及其子类
public abstract class Person {
public abstract void accept(Action visitor);
}
class Man extends Person{
public String name = "男人";
@Override
public void accept(Action visitor) {
visitor.getManConclusion(this);
}
}
class Woman extends Person{
public String name = "女人";
@Override
public void accept(Action visitor) {
visitor.getWomanConclusion(this);
}
}
- 状态类
public abstract class Action {
public abstract void getManConclusion(Man concreteElementA);
public abstract void getWomanConclusion(Woman concreteElementA);
}
class Success extends Action{
private String name = "成功";
@Override
public void getManConclusion(Man concreteElementA) {
System.out.println(concreteElementA.name + this.name + "时,背后多半有一个伟大的女人。");
}
@Override
public void getWomanConclusion(Woman concreteElementA) {
System.out.println(concreteElementA.name + this.name + "时,背后多半有一个不成功的男人。");
}
}
class Failing extends Action{
private String name = "失败";
@Override
public void getManConclusion(Man concreteElementA) {
System.out.println(concreteElementA.name + this.name + "时,闷头喝酒,谁也不用劝。");
}
@Override
public void getWomanConclusion(Woman concreteElementA) {
System.out.println(concreteElementA.name + this.name + "时,眼泪汪汪,谁也劝不了。");
}
}
class Amativeness extends Action{
private String name = "恋爱";
@Override
public void getManConclusion(Man concreteElementA) {
System.out.println(concreteElementA.name + this.name + "时,凡是不懂也要装懂。");
}
@Override
public void getWomanConclusion(Woman concreteElementA) {
System.out.println(concreteElementA.name + this.name + "时,遇事懂也装不懂。");
}
}
- 对象结构
public class ObjectStructure {
private List<Person> list = new LinkedList<>();
public void add(Person person){
list.add(person);
}
public void remove(Person person){
list.remove(person);
}
public void display(Action visitor){
for(Person p:list){
p.accept(visitor);
}
}
}
- 调用方法
public static void main(String[] args) {
ObjectStructure objectStructure = new ObjectStructure();
objectStructure.add(new Man());
objectStructure.add(new Woman());
Success action = new Success();
objectStructure.display(action);
Failing failing = new Failing();
objectStructure.display(failing);
Amativeness amativeness = new Amativeness();
objectStructure.display(amativeness);
}
男人成功时,背后多半有一个伟大的女人。
女人成功时,背后多半有一个不成功的男人。
男人失败时,闷头喝酒,谁也不用劝。
女人失败时,眼泪汪汪,谁也劝不了。
男人恋爱时,凡是不懂也要装懂。
女人恋爱时,遇事懂也装不懂。
总结
- 访问者模式适用于数据结构相对稳定的系统,它将操作和数据进行了解耦
- 在许多系统中,访问者模式常用于将,算法和数据结构分离的设计,使得后期增加算法比较容易
- 那么缺点就是,设计中,需要一个比较稳定的分类,比如设计中的人的分类,因为如果需要增加一个关于人性别的分类,相对来说就比较困难了。因为你需要在所有“状态”类中增加对应的方法。