23种设计模式之访问者模式

访问者模式的定义

定义: 封装一些作用于某种数据结构中的各元素的操作, 它可以在不改变数据结构的前提下定义作用于这些元素的新的操作

通俗的说, 就是定义一个访问者角色, 当对指定角色进行访问时要通过访问者进行访问

其类图如下:

23种设计模式之访问者模式

 

各角色说明:

  1. Vistor 抽象访问者: 抽象类或接口, 声明访问者可以访问哪些元素, 具体到程序中就是 visit 方法的参数定义哪些对象是可以被访问的
  2. ConcreteVistor 具体访问者: 它影响访问者访问到一个类后该怎么干, 要做什么事
  3. Element 抽象元素: 接口或抽象类, 声明接受哪一类访问者访问, 程序上是通过 accept 方法中的参数来定义的
  4. ConcreteElement 具体元素: 实现 accept方法, 通常是 visitor.visit(this); 基本上都形成一种模式了
  5. ObjectStruture 结构对象: 元素的生成者, 一般容纳在多个不同类、不同接口的容器, 项目中一般很少抽象出这个角色

抽象元素代码:

23种设计模式之访问者模式

 

具体元素代码:

23种设计模式之访问者模式

 

抽象访问者代码:

23种设计模式之访问者模式

 

具体访问者代码:

23种设计模式之访问者模式

 

结构对象用来产生不同的元素对象, 代码如下:

23种设计模式之访问者模式

 

场景类代码:

23种设计模式之访问者模式

 

通过增加访问者, 这要是具体元素就非常容易访问, 对元素的遍历就更加容易了, 甭管它是什么对象, 只要它在一个容器中, 都可以通过访问者来访问, 任务集中化.

访问者模式的应用

访问者模式的优点:

  1. 符合单一职责原则. 具体元素角色负责数据的加载, 而访问者角色负责报表的展现, 两个不同的职责非常明确的分离开来, 各自演绎变化
  2. 优秀的扩展. 由于职责分开,继续增加 对数据的操作是非常快捷的.
  3. 灵活性非常高. 例如, 当需要对不同的具体元素进行分别统计时, 使用 instanceof 循环判断当然也可以, 但是现在有一个好办法, 那就是把它丢给访问者,由访问者来进行统计计算

访问者模式的缺点:

  1. 具体元素对访问者公布细节. 访问者要访问一个类就必然要求这个类公布一些方法和数据, 也就是说访问者关注了其他类的内部细节, 这也是迪米特法则所不建议的
  2. 具体元素变更比较困难. 具体元素角色的增加、删除、修改是比较困难的
  3. 违背了依赖倒置原则. 访问者依赖的是具体元素, 而不是抽象元素, 这破坏了依赖倒置原则, 特别是在面向对象的编程中, 抛弃了对 接口的依赖,而直接依赖实现类, 扩展比较难

访问者模式的应用场景:

  1. 一个对象结构包含很多类对象, 它们有不同的接口, 而你想对这些对象实施一些依赖于其具体类的操作, 也就是说用迭代器模式已经不能胜任的情景
  2. 需要对一个对象结构中的对象进行很多不同并且不相关的操作, 而你想避免让这些操作"污染"这些对象的类
  3. 业务规则要求遍历多个不同的对象. 这本身也是访问者模式的出发点, 访问者模式是对迭代器模式的扩充, 可以便利不同的对象, 然后执行不同的操作, 也就是针对访问的对象不同,执行不同的操作.
  4. 访问者模式还有一个 用途, 充当拦截器角色

访问者模式的扩展

1.统计功能

对不同的具体元素进行统计, 针对不同的具体元素针对性统计

比如统计员工工资, 经理和员工的工资情况不同, 使用访问者进行分别计算, 然后可以计算总额等

2.多个访问者

可以定义多个访问者, 每个访问者实现不同的功能

在IVistor 下再定义 接口继承 IVistor, 分别实现各自功能, 使用时传递不同的访问者有不同的表现


访问者模式是一种集中规整模式,特别使用于大规模重构的项目, 在这一个阶段需求已经非常清晰, 原系统的功能点也已经明确, 通过访问者模式可以很容易把一些功能进行梳理, 达到最终目的--功能集中化, 如一个统一的报表运算、UI展现等, 我们还可以与其它模式混编建立一套自己的过滤器或者拦截器

23种设计模式之访问者模式

全文结束