1、概念
访问者模式封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作,属于行为型模式一种。
2、模式结构
- Visitor(抽象访问者):抽象访问者为对象结构中每一个具体元素类ConcreteElement声明一个访问操作,从这个操作的名称或参数类型可以清楚知道需要访问的具体元素的类型,具体访问者则需要实现这些操作方法,定义对这些元素的访问操作。
- ConcreteVisitor(具体访问者):具体访问者实现了抽象访问者声明的方法,每一个操作作用于访问对象结构中一种类型的元素。
- Element(抽象元素):一般是一个抽象类或接口,定义一个Accept方法,该方法通常以一个抽象访问者作为参数。
- ConcreteElement(具体元素):具体元素实现了Accept方法,在Accept方法中调用访问者的访问方法以便完成一个元素的操作。
ObjectStructure(对象结构):对象结构是一个元素的集合,用于存放元素对象,且提供便利其内部元素的方法。
3、使用场景
- 一个对象结构包含很多类操作,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作污染这些对象的类。
定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。
4、优缺点
优点:- 将有关元素对象的访问行为集中到一个访问者对象中,而不是分散在一个个的元素类中,类的职责更加清晰,符合单一职责原则
- 优秀的扩展性,元素类可以通过接受不同的访问者来实现对不同操作的扩展
灵活性高,能够使得用户在不修改现有类的层次结构下,定义该类层次结构的操作
缺点:
- 增加新的元素类很困难,需要在每一个访问者类中增加相应访问操作代码,这违背了开闭原则
元素对象有时候必须暴露一些自己的内部操作和状态,否则无法供访问者访问,这破坏了元素的封装性
5、实例
定义Visitor(抽象访问者)
public interface Visitor { float visit(FoodElement food); float visit(FruitElement fruit);}
定义Element(抽象元素)
public interface Element { float accept(Visitor visitor);}
定义具体元素FruitElement
public class FoodElement implements Element { private float price; private int num; public FoodElement(int num, float price) { this.num = num; this.price = price; } public float getPrice() { return price; } public int getNum() { return num; } @Override public float accept(Visitor visitor) { return visitor.visit(this); }}
定义具体元素FruitElement
public class FruitElement implements Element { private float price; private int num; public FruitElement(int num, float price) { this.num = num; this.price = price; } public float getPrice() { return price; } public int getNum() { return num; } @Override public float accept(Visitor visitor) { return visitor.visit(this); }}
定义具体的ConcreteVisitor
public class ConcreteVisitor implements Visitor { @Override public float visit(FoodElement food) { return food.getNum() * food.getPrice(); } @Override public float visit(FruitElement fruit) { return fruit.getNum() * fruit.getPrice(); }}
定义对象结构ObjectStructure
public class ObjectStructure { private Listlist = new ArrayList<>(); /** * 访问者访问元素的入口 * * @param visitor 访问者 */ public void accept(Visitor visitor) { for (int i = 0; i < list.size(); i++) { Element element = list.get(i); element.accept(visitor); } } /** * 把元素加入到集合 * * @param element 待添加的元素 */ public void addElement(Element element) { list.add(element); } /** * 把元素从集合中移除 * * @param element 要移除的元素 */ public void removeElement(Element element) { list.remove(element); }}
客户端使用
ObjectStructure objectStructure = new ObjectStructure();objectStructure.addElement(new FoodElement(10, 2));objectStructure.addElement(new FruitElement(10, 2));objectStructure.accept(new ConcreteVisitor());