在进行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) { ArrayListlist = 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(依赖倒置原则)。