访问者模式(Visitor Pattern)
Posted 顧棟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了访问者模式(Visitor Pattern)相关的知识,希望对你有一定的参考价值。
访问者模式(Visitor Pattern)
访问者模式的定义
封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
访问者模式的优点
- 扩展性好。由于职责分开,能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
- 复用性好。可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。
- 灵活性好。访问者模式将数据结构与作用于结构上的操作解耦,使得操作集合可相对自由地演化而不影响系统的数据结构。
- 符合单一职责原则。访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一。
访问者模式的缺点
- 增加新的元素类很困难。在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”。
- 违反了依赖倒置原则。访问者模式依赖了具体类,而没有依赖抽象类。
- 具体元素对访问者公布细节,访问者要访问一个类就必然要求这个类公布一些方法和数据,也就是说访问者关注了其
他类的内部细节,这破坏了对象的封装性。这也是是迪米特法则所不建议的。
访问者模式的结构
访问者模式包含以下主要角色。
- 抽象访问者(Visitor)角色:抽象类或者接口,为每个具体元素类对应一个访问操作 visit() ,声明访问者可以访问哪些元素,具体到程序中就是visit方法的参数定义哪些对象是可以被访问的。该操作中的参数类型标识了被访问的具体元素。
- 具体访问者(ConcreteVisitor)角色:实现抽象访问者角色中声明的各个访问操作,它影响访问者访问到一个类后该怎么干,要做什么事情。
- 抽象元素(Element)角色:接口或者抽象类,声明接受哪一类访问者访问,程序上是通过accept方法中的参数来定义的。
- 具体元素(ConcreteElement)角色:实现accept方法,通常是visitor.visit(this),基本上都形成了一种模式了,另外具体元素中可能还包含本身业务逻辑的相关操作。
- 对象结构(Object Structure)角色:元素产生者,一般容纳在多个不同类、不同接口的容器,如List、Set、Map等,在项目
中,一般很少抽象出这个角色。
访问者模式的实现
一般实现
/**
* 抽象元素
*/
public abstract class Element {
/**
* 定义业务逻辑
*/
public abstract void doSomething();
/**
* 允许谁来访问
*/
public abstract void accept(IVisitor visitor);
}
/**
* 具体元素1
*/
public class ConcreteElement1 extends Element {
/**
* 定义业务逻辑
*/
@Override
public void doSomething() {
System.out.println("ConcreteElement1 is doing something");
}
/**
* 允许谁来访问
*/
@Override
public void accept(IVisitor visitor) {
visitor.visit(this);
}
}
/**
* 具体元素2
*/
public class ConcreteElement2 extends Element {
/**
* 定义业务逻辑
*/
@Override
public void doSomething() {
System.out.println("ConcreteElement2 is doing something");
}
/**
* 允许谁来访问
*/
@Override
public void accept(IVisitor visitor) {
visitor.visit(this);
}
}
/**
* 抽象访问者
*/
public interface IVisitor {
/**
* 访问具体元素1
*/
public void visit(ConcreteElement1 el1);
/**
* 访问具体元素2
*/
public void visit(ConcreteElement2 el2);
}
/**
* 具体访问者
*/
public class Visitor implements IVisitor {
@Override
public void visit(ConcreteElement1 el1) {
el1.doSomething();
}
@Override
public void visit(ConcreteElement2 el2) {
el2.doSomething();
}
}
/**
* 结构对象
*/
public class ObjectStructure {
private final List<Element> list = new ArrayList<>();
public void accept(Visitor visitor) {
for (Element element : list) {
element.accept(visitor);
}
}
public void add(Element element) {
list.add(element);
}
public void remove(Element element) {
list.remove(element);
}
}
public static void main(String[] args) {
ObjectStructure objectStructure = new ObjectStructure();
//获得元素对象
Element el1 = new ConcreteElement1();
Element el2 = new ConcreteElement2();
objectStructure.add(el1);
objectStructure.add(el2);
for (int i = 0; i < 5; i++) {
//接受访问者访问
objectStructure.accept(new Visitor());
}
}
适用场景
-
对象结构相对稳定,但其操作算法经常变化的程序。
-
对象结构中的对象需要提供 多种不同 且 不相关的操作,而且要避免让这些操作的变化影响对象的结构。
-
对象结构包含很多类型的对象,希望对这些对象实施一些依赖于其具体类型的操作。
本文主要参考:
- 小傅哥的《重学Java模式》
- 《C语言中文网》设计模式的相关内容
- 《设计模式之禅》第二版 秦小波
以上是关于访问者模式(Visitor Pattern)的主要内容,如果未能解决你的问题,请参考以下文章