原创文章,转载请标明来源。

访问者模式是一个比较简单的模式

背景介绍

很多书或网上文章都会说访问者模式是最复杂的模式之一,在我看来有失偏颇。其实理解后它还是比较简单的。

GOF原文中举了如下的例子:对于一个编译器,需要对“变量赋值”(如 String a = “123”)和“变量访问”(如a.charAt(0))这两种操作做同样的一些处理,比如类型检查、代码格式化、自动完成等。
原汁原味设计模式-访问者Visitor
- VariableRefNode 变量赋值的节点
- AssignmentNode 变量访问的节点
- typeCheck 类型检查
- formatCode 代码格式化
- generateCode 自动完成

这个类图大家都很熟悉了,它跟策略模式很像,但区别是这里的方法数是不固定的,比如后面可能会增加混淆功能,那么就需要给每个类增加混淆方法。这明显违背了开闭原则。

解决方案

修改的方法就是将容易变化的部分进行封装,修改为接口和实现类。即将typeCheck等封装成单独的类。
而对于typeCheck等类,它们需要支持VariableRef和Assignment两种节点,于是它们的类图是这样的:

原汁原味设计模式-访问者Visitor

接下来需要将Node和Visitor关联起来,于是给Node增加一个accecpt方法,参数里是Visitor对象,这样就把操作转移到了Visitor中。

原汁原味设计模式-访问者Visitor
ObjectStructure是一个容器,持有若干个Node。

那么Node类除了将操作转发到Visitor之外,还有没有别的意义呢?这里我们从类命名上可以推断出来,Visitor类是访问其他类的,那么被访问的Node,需要提供自身的数据供Visitor使用。也就是Visitor负责逻辑,Node提供数据。这是拆分类时需要注意的一点。

局限性

访问者模式本身也是为了解决类膨胀的问题,它把A维度上的操作转移到了B维度,但转移后还是存在固化的部分,那就是Visitor中的方法,它有visitA、visitB等多个方法,如果想增加visitC呢?那还是需要改所有Visitor类的代码。因此需要注意:Node类的实现不能频繁变化,由于每个Node的实现类都对应Visitor中的一个visit方法,如果Node类频繁变化,那么是不适用于这个模式的,这时可以考虑使用桥接模式等。

模式的应用

为了套用Visitor模式,我们需要做一些假设。比如手机扫码,我们需要支持条形码、二维码。而扫码引擎有zbar,zxing。我们知道这些扫码引擎能自动识别码的类型,我们假设他们不能自动识别,而是需要我们手动指定。那么这时就能使用访问者模式了。
这里我们可以分析出,条码和二维码是提供数据的角色,zbar和zxing是执行操作的角色。另一方面,码的类型变化可能小,而扫码引擎则很可能新增,于是使用Visitor模式后:
原汁原味设计模式-访问者Visitor

相关文章:

  • 2021-11-09
  • 2022-02-12
  • 2021-10-17
  • 2021-09-30
  • 2022-12-23
  • 2021-12-10
  • 2021-11-08
猜你喜欢
  • 2021-07-31
  • 2021-06-11
  • 2021-12-20
  • 2021-07-27
  • 2021-11-02
相关资源
相似解决方案