本章中,我们了解了访问者模式,以及在 C++ 中可以实现的不同方式。经典的面向对象访问者模式允许在不修改类源代码的情况下,有效地为整个类型层次结构添加一个新的虚函数。层次结构必须设计成可访问的,还可以添加任意数量的操作,并且其实现与对象本身保持分离。
在经典的访问者模式实现中,包含访问层次结构的源代码不需要修改,但在向层次结构添加新类时需要重新编译。非循环访问者模式解决了这个问题,但代价是增加了其他动态转换。另一方面,非循环访问者模式还支持部分访问 —— 忽略某些访问者/访问者组合 —— 而经典的访问者模式要求至少声明所有组合。
对于所有访问者变体而言,扩展性的权衡是需要削弱封装性,并且通常需要授予外部访问者类访问,本应是私有数据成员的权限。
访问者模式经常与其他设计模式结合使用,特别是组合模式,以创建复杂的可访问对象。组合对象将其包含的对象的访问操作进行委托。这种组合模式在对象分解为其最小构成单元时特别有用;例如,用于序列化。
经典的访问者模式在运行时实现双重分派 —— 在执行期间,程序根据两个因素(访问者和访问对象的类型)选择要运行的代码。该模式也可以在编译时以类似方式使用,从而提供有限的反射能力。
在 C++17 中,std::visit 可用于将访问者模式扩展到不属于共同继承层次的类型,甚至实现多重分派。
本章关于访问者模式的内容,原本是本书这本专注于 C++ 惯用法和设计模式的结尾。但如同新星诞生一般,新模式的诞生从未停止 —— 新的领域和新的思想带来了需要解决的新挑战,以及需要发明的新解决方案,它们不断演进和发展,直到编程社区集体达成共识。我们可以自信地指出,这通常是处理某个问题的好方法。我们将详细阐述每种新方法的优点,考虑其缺点,并为其命名,以便我们能够简洁地指代关于该问题、其解决方案及其注意事项的完整知识集合。由此,一种新模式进入了我们的设计工具集和编程词汇中。为了说明这一过程,在接下来也是最后一章中,我们收集了一些为解决并发程序特定问题而出现的模式。