持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情
关键词:行为型 模板方法 template method
模板方法模式由两部分结构组成:抽象父类和具体的实现子类。
核心:父类中封装子类的公用方法,和方法的执行顺序(举例:react 组件的生命周期)。
解决什么问题?
如果对
react
有所了解的话,Component
就是模板方法模式最典型的案例。
模板方法模式有两大作用:复用和扩展。
复用是说,所有的子类可以复用父类中提供的模板方法。
扩展是说,在父类提供功能扩展点 hook,让子类可以在不重写修改父类的情况下,基于扩展点定制功能。
具体实践
模板方法模式建议将算法分解为一系列步骤, 然后将这些步骤改写为方法, 最后在 “模板方法” 中依次调用这些方法。
步骤可以是 抽象的, 也可以有一些默认的实现。 为了能够使用算法, 客户端需要自行提供子类并实现所有的抽象步骤。 如有必要还需重写一些步骤 (但这一步中不包括模板方法自身)。
- 抽象父类中的方法,有些子类由各个子类实现的
abstract
,有些是选填的final
- 可选步骤已有一些默认实现,在需要时可以进行重写
- hook 是内容为空的可选步骤。即使不重写 hook,模板方法也能工作。通常放置在重要步骤方法的前后,提供扩展点。
abstract class AbstractClass { // 模板方法 public templateMethod(): void { this.create(); this.customOperation(); this.update(); this.beforeMount(); this.dealEffect(); this.mount(); this.mounted(); } // 已经在父类中实现 protected create(): void { console.log("父类执行函数 create"); } protected update(): void { console.log("父类让子类覆盖执行操作 update"); } protected mount(): void { console.log("父类执行函数 mount"); } // 必须在子类实现的方法 - 业务定制 protected abstract customOperation(): void; protected abstract dealEffect(): void; // 可选步骤,默认为空,放置在重要步骤方法的前后,提供扩展点 protected beforeMount(): void {} protected mounted(): void {} } class ConcreteClass1 extends AbstractClass { protected customOperation(): void { console.log("子类1必填函数执行:customOperation"); } protected dealEffect(): void { console.log("子类1必填函数执行:dealEffect"); } } class ConcreteClass2 extends AbstractClass { protected customOperation(): void { console.log("子类2必填函数执行:customOperation"); } protected dealEffect(): void { console.log("子类2必填函数执行:dealEffect"); } protected beforeMount(): void { console.log("子类2执行hook beforeMount"); } }
测试代码:
function clientCode(abstractClass: AbstractClass) { abstractClass.templateMethod(); } clientCode(new ConcreteClass1()); console.log(""); clientCode(new ConcreteClass2()); // 父类执行函数 create // 子类1必填函数执行:customOperation // 父类让子类覆盖执行操作 update // 子类1必填函数执行:dealEffect // 父类执行函数 mount // 父类执行函数 create // 子类2必填函数执行:customOperation // 父类让子类覆盖执行操作 update // 子类2执行hook beforeMount // 子类2必填函数执行:dealEffect // 父类执行函数 mount
应用场景
- 方法执行顺序和步骤很固定,只有个别方法需要修改
abstract
。 - 控制子类的扩展,父类只在特定点调用 hook,只允许在这些地方进行拓展。
当我们使用模板方法模式编写代码时,由父类控制哪些方法在什么时候被调用,子类只负责提供一些设计上的细节和方法。
参考资料