[设计模式] 行为型 | 11.访问者模式
1.模式定义
- 访问者模式(Visitor Pattern):表示一个作用于某对象结构中的各元素的操作,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
- 访问者模式是一种对象行为型模式
2. 模式结构
访问者模式包含如下角色:
- Visitor(抽象访问者)
- ConcreteVisitor(具体访问者)
- Element(抽象元素)
- ConcreteElement(具体元素)
- ObjectStructure(对象结构)
抽象访问者类示例代码
public abstract class Visitor {
public abstract void visit(ConcreteElementA elementA);
public abstract void visit(ConcreteElementB elementB);
public void visit(ConcreteElementC elementC) {
//元素ConcreteElementC操作代码
}
}
具体访问者类示例代码
public class ConcreteVisitor extends Visitor {
public void visit(ConcreteElementA elementA) {
//元素ConcreteElementA操作代码
}
public void visit(ConcreteElementB elementB) {
//元素ConcreteElementB操作代码
}
}
抽象元素类示例代码
public interface Element {
public void accept(Visitor visitor);
}
具体元素类示例代码
public class ConcreteElementA implements Element {
public void accept(Visitor visitor) {
visitor.visit(this);
}
public void operationA() {
//业务方法
}
}
对象结构示例代码
import java.util.*;
public class ObjectStructure
{
private ArrayList<Element> list = new ArrayList<Element>(); //定义一个集合用于存储元素对象
//接受访问者的访问操作
public void accept(Visitor visitor) {
Iterator i=list.iterator();
while(i.hasNext()) {
((Element)i.next()).accept(visitor); //遍历访问集合中的每一个元素
}
}
public void addElement(Element element) {
list.add(element);
}
public void removeElement(Element element) {
list.remove(element);
}
}
3.模式分析
- 它为操作存储不同类型元素的对象结构提供了一种解决方案
- 用户可以对不同类型的元素施加不同的操作
- 双重分派机制
(1) 调用具体元素类的accept(Visitor visitor)方法,并将Visitor子类对象作为其参数
(2) 在具体元素类accept(Visitor visitor)方法内部调用传入的Visitor对象的visit()方法,例如visit(ConcreteElementA elementA),将当前具体元素类对象(this)作为参数,例如visitor.visit(this)
(3) 执行Visitor对象的visit()方法,在其中还可以调用具体元素对象的业务方法
4.模式实例
-
购物车:实例说明
顾客在超市中将选择的商品,如苹果、图书等放在购物车中,然后到收银员处付款。在购物过程中,顾客需要对这些商品进行访问,以便确认这些商品的质量,之后收银员计算价格时也需要访问购物车内顾客所选择的商品。此时,购物车作为一个ObjectStructure(对象结构)用于存储各种类型的商品,而顾客和收银员作为访问这些商品的访问者,他们需要对商品进行检查和计价。不同类型的商品其访问形式也可能不同,如苹果需要过秤之后再计价,而图书不需要。使用访问者模式来设计该购物过程。 -
购物车:参考类图
5.模式优缺点:
优点
- 增加新的访问操作很方便
- 将有关元素对象的访问行为集中到一个访问者对象中,而不是分散在一个个的元素类中,类的职责更加清晰
- 让用户能够在不修改现有元素类层次结构的情况下,定义作用于该层次结构的操作
缺点
- 增加新的元素类很困难
- 破坏了对象的封装性
6.使用场景:
- 一个对象结构包含多个类型的对象,希望对这些对象实施一些依赖其具体类型的操作
- 需要对一个对象结构中的对象进行很多不同的且不相关的操作,并需要避免让这些操作“污染”这些对象的类,
- 也不希望在增加新操作时修改这些类
- 对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作