TypeScript | 设计模式11 - 模版方法模式

这是我参与11月更文挑战的第16天,活动详情查看:2021最后一次更文挑战

模版方法模式

定义:一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。它是一种类行为型模式。

模式的结构

抽象类/抽象模版

  • 模版方法:定义算法的骨架,按某种顺序调用其包含的基本方法。如一个Save()方法中其中按顺序调用了beforeCreate() ,create(),afterCreate()三个方法。
 abastract class User {
   save() {
     beforeCreate();
     create();
     afterCreate();
   }
   
   beforeCreate();
   create();
   afterCreate();
 }
复制代码
  • 基本方法:是整个算法中的一个步骤,主要包含以下几种类型:

    • 抽象方法:在抽象类中声明,由具体子类实现
    • 具体方法:在抽象类中已经实现,在具体子类中可以继续继承或重写它
    • 钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种

具体子类/具体实现

具体的实现类,实现抽象类中所定义的抽象方法和钩子方法

abstract class AbstractUser {
​
    public templMethod(){
        this.abMethod1();
        this.factMethod();
        if(this.hookMethod()) {
            this.abMethod2();
        }
    }
​
    // 2个抽象方法
    abstract abMethod1():any;
    abstract abMethod2():any;
​
    abstract hookMethod():any;
​
    // 1个具体方法
    factMethod() {
        console.log('抽象类中执行了具体方法。。。')
    }
}
​
class User extends AbstractUser {
    hookMethod() {
        return true;
    }
    abMethod1() {
        console.log('抽象方法1的实现被调用')
    }
    abMethod2() {
        console.log('抽象方法2的实现被调用')
    }
}
​
(()=>{
    const abUser = new User();
    abUser.templMethod();
})();
复制代码

从Demo代码中可以看出,通过扩展子类中的部分内容来改变部分算法,钩子就是用于判断的。

主要优点

  • 封装不变的部分,扩展可变的部分。
  • 公共部分在父类中实现,便于代码复用
  • 部分方法由子类实现,因此子类可以通过扩展方式增加相应的功能,符合开闭的原则

主要缺点

  • 不同的功能都需要定义一个子类,可能导致类的个数增多,增加系统实现的复杂度
  • 父类的抽象方法由子类实现,子类的执行结果影响父类的结果,可能导致一种反向的控制结构,提高代码阅读难度
  • 通过继承方式,若父类增加抽象方法,则所有子类都需要修改

使用场景:

  • 某些过程是固定的,但是其中个别部分是易变的,可以使用模版方法模式,将容易变的部分抽象出来,供子类实现
  • 当多个子类存在公共的行为时,可以将其提取并集中到一个公共父类以避免代码重复。
  • 当需要控制子类的扩展时,模版方法只在特定点调用钩子操作,这样就只允许在这些点进行扩展

如,我们经常去银行办理业务时,需要经历:取号,排队,办理具体业务,评价。除了办理业务不同可以在子类中实现,其他过程都一致的可以在父类中处理。

猜你喜欢

转载自juejin.im/post/7031187541223014436