传统方式的问题分析
1.如果系统比较小,还是OK的,但是考虑到系统增加越来越多的新的功能时,对代码修改是比较大的。违反了OCP原则。
2.扩展性不好,比如增加了新的人员类型,或者管理方法,都不好做。
作用域这些元素的新的操作。
2.主要将数据结构与数据操作分离,解决数据结构和操作耦合性的问题。
3.访问者模式的基本工作原理是:在被访问的类里面加一个对外提供接待访问者的接口。
4.访问者模式主要应用场景是:需要对一个对象结构找那个的对象进行很多不同操作(这些操作彼此没有关联),同时需要避免让这些操作“污染”这些对象的类,可以选用访问者模式解决。
代码实现
package com.visitor; public abstract class Action { //得到男性的测评 public abstract void getManResult(Man man); //得到女性的测评 public abstract void getWomanResult(Woman woman); }
package com.visitor; public class Success extends Action { @Override public void getManResult(Man man) { System.out.println("男人给的评价是很成功"); } @Override public void getWomanResult(Woman woman) { System.out.println("女人给的评价是很成功"); } }
package com.visitor; public class Fail extends Action { @Override public void getManResult(Man man) { System.out.println("男人给的评价是很失败"); } @Override public void getWomanResult(Woman woman) { System.out.println("女人给的评价是很失败"); } }
package com.visitor; public abstract class Person { //提供一个方法,让访问者可以访问 public abstract void accept(Action action); }
package com.visitor; public class Man extends Person { @Override public void accept(Action action) { action.getManResult(this); } }
package com.visitor; import java.util.TreeSet; /** * 说明: * 1.这里我们使用到了双分派,即首先在客户端程序中,将具体状态作为参数传递到Woman中(第一次分派) * 2.然后 Woman 类调用作为参数的“具体方法”中方法getWomanResult,同时将自己this作为参数传入,完成第二次分派。 */ public class Woman extends Person { @Override public void accept(Action action) { action.getWomanResult(this); } }
package com.visitor; import java.util.LinkedList; import java.util.List; /** * 数据结构,管理了很多人(有man和woman) */ public class ObjectStructrue { //维护了一个集合 private List<Person> persons=new LinkedList<>(); //增加到LinkedList中 public void attach(Person person){ persons.add(person); } //移除 public void detach(Person person){ persons.remove(person); } //显示测评情况 public void display(Action action){ for (Person p: persons) { p.accept(action); } } }
package com.visitor; import sun.java2d.opengl.OGLContext; import java.io.ObjectOutputStream; public class Client { public static void main(String[] args) { //创建ObjectStructure ObjectStructrue objectStructrue = new ObjectStructrue(); objectStructrue.attach(new Man()); objectStructrue.attach(new Woman()); //成功 Success success = new Success(); objectStructrue.display(success); System.out.println("======================"); //失败 Fail fail = new Fail(); objectStructrue.display(fail); } }
运行结果:
男人给的评价是很成功 女人给的评价是很成功 ====================== 男人给的评价是很失败 女人给的评价是很失败
-上面提到了双分派,所谓双分派是指不管类怎样变化,我们都能找到期望的方法运行,双分派意味着得到执行的操作取决于请求的种类和两个接受者的类型。
-以上述实例为例,假设我们需要添加一个undetermined的状态类,考察Man类和Woman类的反应,由于使用了双分派,只需要增加一个Action子类即可在客户端调用即可,不需要改动任何代码。
访问者模式的注意事项和细节
优点:
1.访问者模式符合单一职责原则、让陈旭具有优秀的扩展性、灵活性非常高
2.访问者模式可以对功能进行统一,可以做报表、UI、拦截器与过滤器,适用于数据结构相对稳定的系统
缺点
1.具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的,这样造成了具体元素变更比较困难
2.违背了依赖倒转原则,访问者依赖的是具体元素,而不是抽象元素
3.因此,如果一个系统有比较稳定的数据届酷狗,又有经常变化的功能需求,那么访问者模式就是比较合适的。