关于模板方法模式我所知道的

204 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情

关键词:行为型 模板方法 template method

模板方法模式由两部分结构组成:抽象父类和具体的实现子类。

核心:父类中封装子类的公用方法,和方法的执行顺序(举例:react 组件的生命周期)。

解决什么问题?

如果对react有所了解的话,Component 就是模板方法模式最典型的案例。

模板方法模式有两大作用:复用和扩展。

复用是说,所有的子类可以复用父类中提供的模板方法。

扩展是说,在父类提供功能扩展点 hook,让子类可以在不重写修改父类的情况下,基于扩展点定制功能。

具体实践

模板方法模式建议将算法分解为一系列步骤, 然后将这些步骤改写为方法, 最后在 “模板方法” 中依次调用这些方法。

步骤可以是 抽象的, 也可以有一些默认的实现。 为了能够使用算法, 客户端需要自行提供子类并实现所有的抽象步骤。 如有必要还需重写一些步骤 (但这一步中不包括模板方法自身)。

  1. 抽象父类中的方法,有些子类由各个子类实现的 abstract,有些是选填的 final
  2. 可选步骤已有一些默认实现,在需要时可以进行重写
  3. 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,只允许在这些地方进行拓展。

当我们使用模板方法模式编写代码时,由父类控制哪些方法在什么时候被调用,子类只负责提供一些设计上的细节和方法。

参考资料

refactoringguru 模板方法模式