敏捷软件开发 - 原则、模式与实践 —— 设计模式(十一)VISITOR模式

本文为敏捷软件开发 - 原则、模式与实践系列的一部分。

本文对应原书第28章

VISTOR模式系列允许在不更改现有层次结构的情况下向其中增加新方法。

该系列中的模式如下

  • VISITOR模式
  • ACYCLIC VISITOR模式
  • DECORATOR模式
  • EXTENSION ObJECT模式

VISITOR模式

图1

这个结构,可以通过增加新的ModemVisitor派生类来增加新的操作系统配置函数,而完全不用对Modem层次结构进行更改。所以,VISITOR模式使用ModemVisitor的派生类代替了Modem层次结构中的方法。

这之所以被称为双重分发是因为它涉及了两个多态分发。第一个分发是accept函数。该分发辨别出所调用的accept方法所属对象的类型。第二个分发是visit方法,它辨别出要执行的特定函数。这两个分发赋予了VISITOR模式非常快的执行速度。

VISITOR模式中的两次分发形成了一个功能矩阵。在Modem的例子中,矩阵的一条轴是不同类型的Modem。另一条轴是不同类型的操作系统。该矩阵的每个单元都被一项功能填充,该功能描绘了如何把特定的Modem初始化为可以在特定的操作系统中使用。

ACYCLIC VISITOR模式

如果程序中要更改的层次结构不需要经常地增加新的派生类,那么VISITOR模式工作的很好。但是,如果被访问层次结构非常不稳定,经常需要创建许多新的派生类,那么每当向被访问层次结构中增加一个新的派生类时,就必须要更改并且重新编译Visitor基类以及它的所有派生类。在C++中,情况甚至更糟。每当增加任何一个新的派生类时,整个被访问层次结构就必须要被重新编译、重新部署。

可以使用一个成为ACYCLIC VISITOR模式的变体来解决这个问题。该变体把Visitor基类变成退化的,从而解除了依赖环。这个类中没有任何方法意味着它没有依赖于被访问层次结构的派生类。

图2

由于转型需要花费大量的执行时间,并且这些时间是不可预测的,所以ACYCLIC VISITOR模式不适用于严格的实时系统。该模式的复杂性可能同样会使它不适用于其他的系统。但是,对于那些被访问的层次结构不稳定,并且增量编译比较重要的系统来说,该模式是一个不错的选择。

正像VISITOR模式创建了一个功能矩阵(一个轴是被访问的类型,另一个轴是要执行的功能)一样,ACYCLIC VISITOR模式创建了一个稀疏矩阵。访问者类不需要针对每一个被访问的派生类都实现visit函数。例如,如果Ernie Modem不可以配置在UNIX中,那么UnixModemConfigurator就不会实现ErnieVisitor接口。因此,ACYCLIC VISITOR模式允许我们忽略某些派生类和功能的组合。有时,这可能是一个有用的优点。

DECORATOR模式

另一个可以在不改变现有类层次结构的情况下向其中增加新方法的模式是DECORATOR模式。

图3

ModemDecorator子类的dial方法首先执行自己的特殊操作,然后委托调用它包含的Modem实例
的dial方法。

EXTENSION OBJECT模式

还有另外一种方法可以在不更改类层次结构的情况下向其中增加功能,那就是使用EXTENSION OBJECT模式。这个模式虽然比其他模式复杂一些,但是它也更强大、更灵活一些。层次结构中的每个对象都持有一个特定扩展对象(extension object)的列表。同时,每个对象也提供一个通过名字查找扩展对象的方法。扩展对象提供了操作原始层次结构对象的方法。

例如,再次假设我们有一个材料单系统。我们想让该层次结构中的每个对象都具有创建表示自身的XML的能力。我们可以把toXML方法放到层次结构中,但是这回违反SRP。我们不希望把有关XML的内容和有关BOM的内容放到同一个类中。虽然我们可以使用VISITOR模式来创建XML,但是这无法使我们把针对每种不同类型BOM对象的XML生成代码分离。在VISITOR模式中,针对每个BOM类的所有XML生成代码都会在同一个VISITOR对象中。

EXTENSION OBJECT模式提供了一个实现这个目标的优雅方案。下图展示了具有两个不同类型扩展对象的BOM层次结构。一种扩展对象把BOM对象转换成XML。另一个扩展对象把BOM对象转换成CSV。第一种扩展对象通过getExtension("XML")获得,第二种扩展对象通过getExtension("CSV")获得。图中<>表示一个标记接口(也就是没有任何方法的接口)。

图4

结论

VISITOR模式是由诱惑力的。在它们面前很容易会失去自制力。如果它们有用就去使用它们,但是请对它们的必要性保持健康的怀疑。通常,可以使用VISITOR模式解决的问题往往也可以使用更简单的方法解决。

完整内容请查看敏捷软件开发 - 原则、模式与实践系列

你可能感兴趣的:(敏捷软件开发 - 原则、模式与实践 —— 设计模式(十一)VISITOR模式)