在进行Coding时,常常遇到这样一种情况:设计的ADT,将来可能要扩展某些操作,但根据OCP原则,不应当修改已经实现的代码,所以需要提前留下扩展手段。设计模式中的Visitor模式就是契合这样一种设计理念的方法。
先看它的UML模型:
模型看起来有些复杂,不妨先明确几个概念:
Visitor模式的实质
1、封装一些数据结构的各元素操作,降低操作间的耦合性。
2、将数据结构和数据操作解耦,使得易于扩展。
Visitor模式角色分工
1、Visitor: 抽象访问者, 在重载的visit方法中声明可以访问的对象
2、Concrete Visitor: 实现访问者对一个具体元素的操作
3、Element: 抽象元素, 提供重载的accpet方法(意义在于赋予访问权限,提高安全性)
4、Concrete Element: 实现accept方法
5、Object structure: 容纳多个Element
Attention: Visitor模式的基本流程是Element是ADT,但不希望在其中实现一些操作(因为与本身关联度低),所以留了一个后门(accept方法),可以让特定的类获得它本身,从而进行相应的操作。特定的类同时需要有相应的进入后门的办法(visit方法),才能实现。
一个例子:
统计学生中男女生各自的数量
abstract class Student {
...
public abstract void accept(Visitor visitor);
...
}
class MaleStudent {
...
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
class FemaleStudent {
...
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
interface Visitor {
public void visit(MaleStudent ms);
public void visit(FemaleStudent fs);
}
class CountVisitor implements Visitor {
private int male = 0;
private int female = 0;
@Override
public void visit(MaleStudent ms) {
male++;
}
public void visit(FemaleStudent fs) {
female++;
}
}
public class Main {
public static void main(String[] args) {
ArrayList<Student> list = new ArrayList<>();
MaleStudent a = ...;
FeMaleStudent b = ...;
list.add(a);
list.add(b);
Visitor v = new CountVisitor();
for (Student s : list) {
s.accept(v);
}
}
}
优缺点:
1、优点:将操作与数据分离,防止新操作污染原ADT的一致性。易于扩展。
2、缺点:visitor模式依赖具体实现(Visitor根据Student具体的类型决定哪个方法),违背了DIP(依赖倒置原则)。