持续创作,加速成长!这是我参与「掘金日新计划 · 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,只允许在这些地方进行拓展。
当我们使用模板方法模式编写代码时,由父类控制哪些方法在什么时候被调用,子类只负责提供一些设计上的细节和方法。
参考资料