访问者模式的概念
访问者模式(Visitor Pattern)是GoF(Gang of Four,即四位作者Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides)提出的23种设计模式中的一种,属于行为模式。它表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
访问者模式涉及以下几个角色:
- Visitor(抽象访问者):为该对象结构中具体元素角色声明一个访问操作接口。
- ConcreteVisitor(具体访问者):实现Visitor声明的接口。
- Element(抽象元素):定义一个接受访问操作(accept()),它以一个访问者(Visitor)作为参数。
- ConcreteElement(具体元素):实现了Element所定义的接受操作接口。
- ObjectStructure(结构对象):能枚举它的元素,并可以提供一个高层接口以允许访问者访问它的元素。
访问者模式的优缺点
优点:
- 符合单一职责原则:访问者模式中的操作通常与元素类本身关系不大,且是易变的。使用访问者模式可以将这些操作封装在访问者中,使得元素类更加单一且易于维护。
- 优秀的扩展性:元素类可以通过接受不同的访问者来实现对不同操作的扩展,无需修改元素类本身。
缺点:
- 具体元素对访问者公布细节:违反了迪米特原则(Law of Demeter),即一个对象应该对其他对象保持最少的了解。
- 具体元素变更比较困难:由于访问者模式依赖于元素类的接口,因此如果元素类的接口发生变化,可能需要修改所有的访问者类。
- 违反了依赖倒置原则:访问者模式通常依赖于具体的元素类,而不是抽象接口。
访问者模式的应用场景
- 当一个对象结构包含很多类对象,并且需要对这些对象实施一些依赖于其具体类的操作时,可以使用访问者模式。
- 当需要在一个对象结构中的对象上进行很多不同的且不相关的操作时,为了避免让这些操作"污染"这些对象的类,可以使用访问者模式。
- 当对象结构被多个应用共享时,可以使用访问者模式让每个应用仅包含需要的操作。
代码实现
|---|-------------------------------------------------------|
| | // 抽象访问者接口
|
| | public interface Visitor {
|
| | void visit(ConcreteElementA elementA);
|
| | void visit(ConcreteElementB elementB);
|
| | }
|
| | |
| | // 抽象元素接口
|
| | public interface Element {
|
| | void accept(Visitor visitor);
|
| | }
|
| | |
| | // 具体元素A
|
| | public class ConcreteElementA implements Element {
|
| | @Override
|
| | public void accept(Visitor visitor) {
|
| | visitor.visit(this);
|
| | }
|
| | |
| | // 元素A的具体操作
|
| | public void operationA() {
|
| | System.out.println("ConcreteElementA operationA");
|
| | }
|
| | }
|
| | |
| | // 具体元素B
|
| | public class ConcreteElementB implements Element {
|
| | @Override
|
| | public void accept(Visitor visitor) {
|
| | visitor.visit(this);
|
| | }
|
| | |
| | // 元素B的具体操作
|
| | public void operationB() {
|
| | System.out.println("ConcreteElementB operationB");
|
| | }
|
| | }
|
| | |
| | // 具体访问者
|
| | public class ConcreteVisitor implements Visitor {
|
| | @Override
|
| | public void visit(ConcreteElementA elementA) {
|
| | elementA.operationA();
|
| | System.out.println("Visited ConcreteElementA");
|
| | }
|
| | |
| | @Override
|
| | public void visit(ConcreteElementB elementB) {
|
| | elementB.operationB();
|
| | System.out.println("Visited ConcreteElementB");
|
| | }
|
| | }
|
| | |
| | // 客户端代码
|
| | public class Client {
|
| | public static void main(String[] args) {
|
| | Element elementA = new ConcreteElementA();
|
| | Element elementB = new ConcreteElementB();
|
| | Visitor visitor = new ConcreteVisitor();
|
| | |
| | // 让元素A接受访问者的访问
|
| | elementA.accept(visitor);
|
| | // 让元素B接受访问者的访问
|
| | elementB.accept(visitor);
|
| | }
|
| | }
|
在这个例子中,我们定义了一个Visitor
接口和两个实现了Visitor
接口的visit
方法的ConcreteVisitor
类。我们还定义了一个Element
接口和两个实现了Element
接口的ConcreteElementA
和ConcreteElementB
类。每个具体元素类都实现了accept
方法,该方法接受一个Visitor
对象作为参数,并调用对应的visit
方法。
在客户端代码中,我们创建了两个元素对象和一个访问者对象。然后,我们调用每个元素的accept
方法,将访问者对象作为参数传递。这样,每个元素就会执行对应的visit
方法,完成对元素的访问操作。
这个示例展示了访问者模式的基本结构和用法。在实际应用中,可以根据具体需求对元素和访问者进行扩展和修改。