软件设计模式修炼 -- 模板方法模式

模板方法是结构最简单的行为型设计模式,在抽象类中定义了一个称为模板方法的方法,在这个方法中定义其他基本方法的执行步骤,而基本方法的实现可以放在抽象类,也可以放在其子类

模式动机

现实生活中很多事情的完成过程都包含几个基本步骤,例如请客吃饭,无论吃什么,一般都包含点单、吃东西、买单几个步骤,到底吃什么则具体情况具体分析,在实际环境中由用户动态决定。

既然这几个步骤的次序是固定的,于是我们创建一个新的方法叫“请客”,在其中调用了点单、吃东西和买单,同时指定它们的执行次序,我们称这个“请客”为模板方法,“点单”、“吃东西”、“买单”都是“请客”过程中的一个步骤,它们称为基本方法。其中“吃东西”可以有多种吃法,如吃饭、吃面条、吃烧烤,因此需要提供不同的“吃东西”方法的实现。

假设用代码实现上述方法,我们可以把相同代码放在父类,如“点单”和“买单”,而将不同方法实现放在不同的子类,如“吃东西”,这样一来提高了代码的复用性,还可以利用面向对象的多态性,这就是模板方法模式的模式动机。

模式定义

定义一个操作中算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤

Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.

模式分析

模板方法模式是基于继承的代码复用基本技术,先在抽象类的模板方法中指定执行步骤,将相同步骤对应的方法在抽象父类中实现,而不同的步骤只在抽象父类中进行声明。由于面向对象的多态性,子类中定义的方法将覆盖父类中定义的方法,因此程序运行时,具体子类的基本方法将覆盖父类中定义的基本方法,实现特定的算法。

不过,虽然说子类覆盖了父类的方法实现业务逻辑,但实际上是由父类来控制整个过程,即子类不需要调用父类,而通过父类来调用子类。

由此得模式结构类图如下:

软件设计模式修炼 -- 模板方法模式

抽象类(AbstractClass)中定义一系列基本操作(primitiveOperation),这些基本操作可以是具体的,也可以是抽象的,每一个基本操作对应算法的一个步骤,在其子类中可以重定义并实现一个算法的各个步骤。同时在抽象类中实现了一个模板方法(templateMethod),用于定义一个算法的骨架,调用基本操作。

具体子类(ConcreteClass)用于实现在父类中定义的抽象基本操作以完成子类特定算法的步骤,也可以覆盖在父类中实现的具体基本操作。

基本方法是实现各个步骤的方法,是模板方法的组成部分,基本方法又可以分为三种:

  • 抽象方法

    一个抽象方法由抽象类声明,由其具体子类实现

  • 具体方法

    一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖

  • 钩子方法

    一个钩子方法由一个抽象类或具体类声明并实现,而其子类可能会加以扩展。通常在父类中给出的实现是一个空实现,作为该方法的默认实现,当然也可以提高一个非空的默认实现。

    钩子方法有两类,一类是可以控制具体步骤的执行,比如说我们希望在不同条件下执行模板方法中的不同步骤,就可以定义一个返回类型为布尔值的钩子方法,用于进行条件判断,如果条件满足则执行某一步骤,否则某一步骤不执行

    public void template() {
        open();
        display();
        if(isPrint()) {
            print();
        }
    }
    
    public boolean isPrint(){
        return true;
    }
    

    如果不希望方法执行,可以在其子类在覆盖钩子方法,修改返回值即可。

    还有一类钩子方法是实现体为空的具体方法,子类根据需要覆盖或继承它们,与抽象方法相比,钩子方法的好处在于如果没有覆盖父类中定义的抽象方法,编译仍可以通过。

模式优缺点

模板方法模式的优点:

  • 可以在一个类中形式化地定义算法,而由它的子类实现细节的处理
  • 模板方法模式是一种代码复用的基本技术,在类库设计中尤其重要,它提取类库中的公共行为,将公共行为放在父类,通过子类来实现不同的行为
  • 通过一个父类调用其子类的操作,通过对子类的扩展增加新的行为,符合开闭原则

模板方法模式的缺点:

  • 每个不同的实现都需要定义一个子类,将会导致类的个数增加

版权声明:程序员胖胖胖虎阿 发表于 2022年8月29日 下午4:27。
转载请注明:软件设计模式修炼 -- 模板方法模式 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...