Zer0e's Blog

设计模式之访问者模式

字数统计: 873阅读时长: 3 min
2020/09/08 Share

前言

本篇来讲讲行为型模式的最后一篇,访问者模式。

正文

概念

访问者模式,我们使用一个访问者类来访问数据对象,通常是为了不污染数据对象类,而实现的关键是在数据对象类中提供一个接待访问者的接口。
那这种设计模式了除了不污染原类,很大一部分原因是为了将数据结构与操作相分离。

实现

由于这种设计模式在开发中很少用,一般是在框架或者源码中才会使用到。所以这里我就简单实现一下概念。
首先访问者模式中有几个角色:

  • Visitor(抽象访问者):抽象类或接口,对每一种具体元素类ConcreteElement声明一个操作方法,由具体访问者去实现。
  • ConcreteVisitor(具体访问者):实现抽象访问者的方法。
  • Element(抽象元素):一般会定义一个Accept方法,接受一个visitor对象作为参数。
  • ConcreteElement(具体元素):具体实现抽象元素。
  • ObjectStructure(对象结构):可以是任意一种数据结构,能枚举它包含的元素,并提供一个接口,允许visitor进行访问。

下面我将简单写写代码实现。
首先我们先定义抽象访问者吧。

1
2
3
4
public interface Visitor {
public void visit(ConcreteElementA element);
public void visit(ConcreteElementB element);
}

然后是具体访问者

1
2
3
4
5
6
7
8
9
10
11
public class ConcreteVisitorA implements Visitor{
@Override
public void visit(ConcreteElementA element) {
System.out.println("访问 ElementA");
}

@Override
public void visit(ConcreteElementB element) {
System.out.println("访问 ElementB");
}
}

接着定义抽象元素,有一个accept方法接收一个visitor对象。

1
2
3
public interface Element {
public void accept(Visitor visitor);
}

然后是具体元素

1
2
3
4
5
6
7
8
9
10
11
12
public class ConcreteElementA implements Element{
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public class ConcreteElementB implements Element{
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

我们定义一个对象结构来存放所有的元素,并且定义accept方法来逐个访问元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ObjectStructure {
private ArrayList<Element> elements = new ArrayList<>();

public void accept(Visitor visitor){
for (Element element: elements){
element.accept(visitor);
}
}

public void addElement(Element element){
elements.add(element);
}

public void removeElement(Element element){
elements.remove(element);
}
}

我们编写客户端调用试试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Client {
public static void main(String[] args) {
// 定义元素及访问者
Element elementA = new ConcreteElementA();
Element elementB = new ConcreteElementB();
Visitor visitor = new ConcreteVisitorA();

// 单个元素访问
elementA.accept(visitor);
elementB.accept(visitor);

// 多个元素访问
ObjectStructure objectStructure = new ObjectStructure();
objectStructure.addElement(elementA);
objectStructure.addElement(elementB);
objectStructure.accept(visitor);

}
}

那所以是否定义ObjectStructure取决于你是否需要同时访问多个元素。
书写代码之后,我第一感觉就是耦合较高,访问者与元素之间相互依赖极高。

优缺点

访问者模式的优点在于添加新的访问操作较为方便,无需修改元素类,修改抽象访问者及其具体访问者即可,并且类的职责更加清晰,元素类负责数据,而访问者负责访问,符合单一职责原则。
而缺点就是添加元素类就十分麻烦,添加一个元素类后,需要修改每个访问者的代码,违背了开闭原则。并且在依赖上,具体访问者依赖于具体元素类,没有依赖抽象对象。最后,为了供访问者访问,有时候元素类不得不暴露己类的某些细节,封装性被破坏。

CATALOG
  1. 1. 前言
  2. 2. 正文
    1. 2.1. 概念
    2. 2.2. 实现
    3. 2.3. 优缺点