访问者模式
行为型模式
在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。
介绍
意图: 主要将数据结构与数据操作分离。
主要解决: 稳定的数据结构和易变的操作耦合问题。
何时使用: 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,使用访问者模式将这些封装到类中。
如何解决: 在被访问的类里面加一个对外提供接待访问者的接口。
关键代码: 在数据基础类里面有一个方法接受访问者,将自身引用传入访问者。
具体实现
将观众分为男人和女人,对歌手进行测评,当看完某个歌手表演后,得到他们不同的评价。
第一步:创建抽象Person
public abstract class Person {
//提供一个方法,让访问者可以访问
public abstract void accept(Action action);
}
第二步:具体实现男人和女人类
/**
* 说明:
* 1.这里我们使用了双分派,即在客户端程序中,将具体状态作为参数传递给Woman中.(第一次分派)
* 2.然后Woman类调用作为参数的"具体方法"中的方法getWomanResult,同时将自己(this)作为参数传入,完成第二次分派.
*/
public class Woman extends Person{
@Override
public void accept(Action action) {
action.getWomanResult(this);
}
}
public class Man extends Person {
@Override
public void accept(Action action) {
action.getManResult(this);
}
}
第三步:创建抽象的行为
public abstract class Action {
//得到男性的测评结果
public abstract void getManResult(Man man);
//得到女性的测评结果
public abstract void getWomanResult(Woman woman);
}
第四步:创建具体行为的实现
public class Success extends Action{
@Override
public void getManResult(Man man) {
System.out.println("男人给的评价是:成功");
}
@Override
public void getWomanResult(Woman woman) {
System.out.println("女人给的评价是:成功");
}
}
public class Fail extends Action {
@Override
public void getManResult(Man man) {
System.out.println("男人给的评价是:失败");
}
@Override
public void getWomanResult(Woman woman) {
System.out.println("女人给的评价是:失败");
}
}
第五步:创建对象结构类
public class ObjectStructure {
//维护了一个集合
private List persons = new LinkedList<>();
//增加到list
public void attach(Person p) {
persons.add(p);
}
//删除
public void detach(Person p) {
persons.remove(p);
}
//显示测评情况
public void display(Action action) {
for (Person person : persons) {
person.accept(action);
}
}
}
第六步:创建测试类
public class Client {
public static void main(String[] args) {
//创建ObjectStructure
ObjectStructure objectStructure = new ObjectStructure();
objectStructure.attach(new Man());
objectStructure.attach(new Man());
objectStructure.attach(new Man());
objectStructure.attach(new Woman());
//成功
Success success = new Success();
objectStructure.display(success);
System.out.println("====================");
//失败
Fail fail = new Fail();
objectStructure.display(fail);
}
}
运行如下:
男人给的评价是:成功
男人给的评价是:成功
男人给的评价是:成功
女人给的评价是:成功
====================
男人给的评价是:失败
男人给的评价是:失败
男人给的评价是:失败
女人给的评价是:失败
优点:
1、如果想增加一种评价,只需要继承Action即可,无需改动别的类
2、符合单一职责原则。
3、优秀的扩展性。
4、灵活性。
缺点:
1、具体元素对访问者公布细节,违反了迪米特原则。
2、具体元素变更比较困难。
3、违反了依赖倒置原则,依赖了具体类,没有依赖抽象。