我的设计模式之旅、14 模板方法模式
编程旅途是漫长遥远的,在不同时刻有不同的感悟,本文会一直更新下去。
思考总结
思考问题
- 多个类中包含许多相似代码,只是小部分代码不同。思考如何在保持算法结构完整的情况下去除重复代码。
什么是模板方法模式
模板方法是一种行为设计模式, 它在超类中定义了一个算法的框架,允许子类在不修改结构的情况下重写算法的特定步骤。
模板方法模式:定义一个操作中的算法的骨架,将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤。
![image-20220920130012353](https://xiaonenglife.oss-cn-hangzhou.aliyuncs.com/static/pic/2022/09/20220920130013_image-20220920130012353.png)
含义:
- 模板方法模式建议将算法分解为一系列步骤,然后将这些步骤改写为方法, 最后在“模板方法”中依次调用这些方法。 步骤可以是抽象 的,也可以有一些默认的实现。为了能够使用算法,客户端需要自行提供子类并实现所有的抽象步骤。 如有必要还需重写一些步骤(但这一步中不包括模板方法自身)。
- 抽象步骤必须由各个子类来实现。可选步骤已有一些默认实现,但仍可在需要时进行重写。
还有另一种名为钩子的步骤。钩子是内容为空的可选步骤。 即使不重写钩子,模板方法也能工作。钩子通常放置在算法重要步骤的前后,为子类提供额外的算法扩展点。
何时使用:
- 当你只希望客户端扩展某个特定算法步骤,而不是整个算法或其结构时,可使用模板方法模式。
- 模板方法将整个算法转换为一系列独立的步骤,以便子类能 对其进行扩展,同时还可让超类中所定义的结构保持完整。
- 当多个类的算法除一些细微不同之外几乎完全一样时,你可使用该模式。但只要算法发生变化,你就可能需要修改所有的类。
- 将相似的实现步骤提取到超类中以去除重复代码。子类间各不同的代码可继续保留在子类中。
实现方式:
- 分析目标算法,确定能否将其分解为多个步骤。从所有子类的角度出发,考虑哪些步骤能够通用,哪些步骤各不相同。
- 创建抽象基类并声明一个模板方法和代表算法步骤的一系列抽象方法。 在模板方法中根据算法结构依次调用相应步骤。
- JAVA中可用 final 最终修饰模板方法以防止子类对其进行重写。
- 默认实现会给部分步骤带来好处,子类无需实现那些方法。
- 可考虑在算法的关键步骤之间添加钩子。方便子类提供额外的算法扩展点。
- 为每个算法变体新建一个具体子类,它必须实现所有的抽象步骤,也可以重写部分可选步骤。
应用实例:
- 在造房子的时候,地基、走线、水管都一样,只有在建筑的后期才有加壁橱加栅栏等差异。
- 西游记里面菩萨定好的 81 难,这就是一个顶层的逻辑骨架。
优点:
- 封装不变部分,扩展可变部分。重复代码提取到一个超类中。
- 提取公共代码,便于维护。 你可仅允许客户端重写一个大型算法中的特定部分,使得算法其他部分修改对其所造成的影响减小。
- 行为由父类控制,子类实现。
缺点:
- 每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
- 部分客户端可能会受到算法框架的限制。
- 通过子类抑制默认步骤实现可能会导致违反里氏替换原则。
- 模板方法中的步骤越多,其维护工作就可能会越困难。
与其他模式的关系
- 工厂方法是模板方法的一种特殊形式。同时,工厂方法可以作为一个大型模板方法中的一个步骤。
- 模板方法基于继承机制:它允许你通过扩展子类中的部分内容来改变部分算法。策略基于组合机制:你可以通过对相应行为提供不同的策略来改变对象的部分行为。模板方法在类层次上运作,因此它是静态的。策略在对象层次上运作,因此允许在运行时切换行为。
参考资料
- 《Go语言核心编程》李文塔
- 《Go语言高级编程》柴树彬、曹春辉
- 《大话设计模式》程杰
- 《深入设计模式》亚历山大·什韦茨
- 菜鸟教程