为什么要使用访问者设计模式?
先看一下下面这段代码
class Person{ private String action ; private String name; public Person(String name){ this.name = name; } public String getAction() { return action; } public void setAction(String action) { this.action = action; } public void getConclusion(){ if(action == "Happy"){ System.out.println(name+" feel "+"Happy"); } else if(action == "Exciting"){ System.out.println(name+" feel "+"Exciting"); } else if(action == "Grieved"){ System.out.println(name+" feel "+"Grieved"); } } } public class Client { public static void main(String [] args){ Person person = new Person("jeason"); person.setAction("Happy"); person.getConclusion(); } }
如果需要添加一种feeling那么需要去改动Person类,这里违背了开放封闭原则,getConclusion()需要对每种feeling都分别做操作,这里违背了单一职责原则.现在我们利用访问者模
式就可以就可以避免违反的两种原则.
什么是访问者设计模式?
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
涉及角色:
1.Visitor 抽象访问者角色,为该对象结构中具体元素角色声明一个访问操作接口。该操作接口的名字和参数标识了发送访问请求给具体访问者的具体元素角色,这样访问者就可以通过该元素角色的特定接口直接访问它。
2.ConcreteVisitor.具体访问者角色,实现Visitor声明的接口。
3.Element 定义一个接受访问操作(accept()),它以一个访问者(Visitor)作为参数。
4.ConcreteElement 具体元素,实现了抽象元素(Element)所定义的接受操作接口。
5.ObjectStructure 结构对象角色,这是使用访问者模式必备的角色。它具备以下特性:能枚举它的元素;可以提供一个高层接口以允许访问者访问它的元素;如有需要,可以设计成一个复合对象或者一个聚集(如一个列表或无序集合)。
访问者模式的几个特点:
访问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化。
怎么使用访问者设计模式?
我们根据之前的需求和访问者模式的概念设计出UML:
具体代码:
State.class
public abstract class State { public abstract void eflectPerson(Person person); }
Happy.class
public class Happy extends State{ @Override public void eflectPerson(Person person) { // TODO Auto-generated method stub System.out.println(person.getName()+" feel happy"); } }
Grieved.class
public class Grieved extends State{ @Override public void eflectPerson(Person person) { // TODO Auto-generated method stub System.out.println(person.getName()+" feel grieved"); } }
Exciting.class
public class Exciting extends State{ @Override public void eflectPerson(Person person) { // TODO Auto-generated method stub System.out.println(person.getName()+" feel exciting"); } }
Person.class
public class Person { private String name; public Person(String name){ this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } //双分派 public void receiveState(State state){ state.eflectPerson(this); } }
这里解释一下什么叫双分派:假设有A,B两个对象,对象A中有一个方法需要用到对象B的引用,而在这个方法中去调用对象B的方法会用到对象A的引用。它使得执行结果不仅取决
于B类而且还取决于A类.
PersonStructure.class
public class PersonStructure { private ArrayList<Person> arrayList = new ArrayList<Person>(); public void addPerson(Person person){ arrayList.add(person); } public void remove(Person person){ arrayList.remove(person); } public void displayPersonName(){ for(Person p : arrayList){ System.out.println("person name "+p.getName()); } } public void receiveState(State state){ for(Person p : arrayList){ p.receiveState(state); } } }
Client.class
public class Client { public static void main(String [] args){ Person p1 = new Person("jeason"); Person p2 = new Person("neo"); Person p3 = new Person("kuku"); PersonStructure personStructure = new PersonStructure(); personStructure.addPerson(p1); personStructure.addPerson(p2); personStructure.addPerson(p3); personStructure.displayPersonName(); personStructure.receiveState(new Happy()); } }
最后输出:
person name jeason
person name neo
person name kuku
jeason feel happy
neo feel happy
kuku feel happy