Table Of Content
访问者模式的概念和具体实现
访问者模式中对象结构存储了不同类型的元素对象,以供不同访问者访问。访问者模式包括两个层次结构,一个是访问者层次结构,提供了抽象访问者和具体访问者,一个是元素层次结构,提供了抽象元素和具体元素。相同的访问者可以以不同的方式访问不同的元素,相同的元素可以接受不同访问者以不同访问方式访问。在访问者模式中,增加新的访问者无须修改原有系统,系统具有较好的可扩展性。
访问者模式在不破坏类的前提下,为类提供增加新的新操作,其实现的关键是双分派(Double-Dispatch)的技术。 在访问者模式中 accept()操作是一个双分派的操作。具体调用哪一个具体的accept()操作,体现在handleRequest方法,有两个决定因素:
1)Element的类型。因为 accept()是多态的操作,需要具体的 Element 类型的子类才可以决定到底调用哪一个accept()实现,取决于对象结构类中添加的元素集合;
2)Visitor的类型。accept()操作有一个参数(Visitor visitor),要决定了实际传进来的 Visitor 的实际类别才可以决定具体是调用哪个 VisitConcrete()实现,取决于客户端进行访问的访问者身份。
//访问者接口
interface Visitor {
/**
* 访问ConcreteElementA,相当于为ConcreteElementA添加的新功能
*/
public void visitConcreteElementA(ConcreteElementA elementA);
/**
* 访问ConcreteElementB,相当于为ConcreteElementB添加的新功能
*/
public void visitConcreteElementB(ConcreteElementB elementB);
}
//元素对象抽象类
abstract class Element {
//接受访问者的访问
public abstract void accept(Visitor visitor);
}
//模拟A访问者
class ConcreteVisitorA implements Visitor {
@Override
public void visitConcreteElementA(ConcreteElementA elementA) {
/**
* 把访问ConcreteElementA时,需要执行的功能在这里进行实现 可能需要访问元素已有的功能,比如:operationA()
*/
System.out.println("ConcreteVisitorA 访问 ==> ConcreteElementA 对象");
}
@Override
public void visitConcreteElementB(ConcreteElementB elementB) {
/**
* 把访问ConcreteElementB时,需要执行的功能在这里进行实现 可能需要访问元素已有的功能,比如:operationB()
*/
System.out.println("ConcreteVisitorA 访问 ==> ConcreteElementB 对象");
}
}
//模拟B访问者
class ConcreteVisitorB implements Visitor {
@Override
public void visitConcreteElementA(ConcreteElementA elementA) {
/**
* 把访问ConcreteElementA时,需要执行的功能在这里进行实现
* 可能需要访问元素已有的功能,比如:operationA()
*/
System.out.println("ConcreteVisitorB 访问 ==> ConcreteElementA 对象");
}
@Override
public void visitConcreteElementB(ConcreteElementB elementB) {
/**
* 把访问ConcreteElementB时,需要执行的功能在这里进行实现 可能需要访问元素已有的功能,比如:operationB()
*/
System.out.println("ConcreteVisitorB 访问 ==> ConcreteElementB 对象");
}
}
//元素访问对象A
class ConcreteElementA extends Element {
@Override
public void accept(Visitor visitor) {
// 回调访问者对象的相应方法
visitor.visitConcreteElementA(this);
}
/**
* 示例方法,表示元素已有的功能实现
*/
public void operationA() {
System.out.println("执行ConcreteElementA已有的operationA方法.");
}
}
//元素访问对象B
class ConcreteElementB extends Element {
@Override
public void accept(Visitor visitor) {
// 回调访问者对象的相应方法
visitor.visitConcreteElementB(this);
}
/**
* 示例方法,表示元素已有的功能实现
*/
public void operationB() {
System.out.println("执行ConcreteElementB已有的operationB方法.");
}
}
//元素对象集合类,包括元素添加和元素访问
class ObjectStructure {
/**
* 示意,表示对象结构,可以是一个组合结构或者集合
*/
private Collection<Element> col = new ArrayList<>();
/**
* 示意方法,提供给客户端操作的高层接口,让访问者对对象结构中的所有元素进行访问
*/
void handleRequest(Visitor visitor) {
//循环对象结构中的元素,进行访问
for (Element element : col) {
element.accept(visitor);
}
}
/**
* 示意方法,组建对象结构,向对象结构中添加元素
*/
void addElement(Element element) {
this.col.add(element);
}
}
//客户端
class Client {
public static void main(String[] args) {
//创建对象结构
ObjectStructure os = new ObjectStructure();
//为对象结构中添加元素对象
os.addElement(new ConcreteElementA());
os.addElement(new ConcreteElementB());
//创建访问者
Visitor visitor = new ConcreteVisitorA();
//调用对象结构的业务处理方法
os.handleRequest(visitor);
}
}
访问者模式的场景举例
一个商场(SuperMarket),通常都会包括(当然还会包含一些其他的组成部分):商店(Store)、监控室(MonitoringRoom)、卫生间(WaterCloset)。商场的访问者大致可以分为两大类:顾客(Customer)、商场工作人员(MarketStaff)。顾客可以逛商店、上卫生间,但却不能进入监控室;工作人员可以进入监控室、上卫生间,但却不能像顾客一样逛商店(除非他不想干了),也就是说对于商场的同一个地点,不同的访问者有不同的行为权限,而且访问者的种类很有可能需要根据时间的推移发生变化(没准哪天,工商局的人要来视察呢!此时就需要增加工商局人员的访问者了。)
参考博文:https://blog.csdn.net/pengjunlee/article/details/54429325