模板模式

Posted by on Saturday, 2020年04月11日

[TOC]

记录来源:《设计模式之禅》作者:秦小波

定义

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

模板方法模式确实非常简单,仅仅使用了Java的继承机制,但它是一个应用非常广泛的 模式。其中,AbstractClass叫做抽象模板,它的方法分为两类:

● 基本方法

基本方法也叫做基本操作,是由子类实现的方法,并且在模板方法被调用。

● 模板方法

可以有一个或几个,一般是一个具体方法,也就是一个框架,实现对基本方法的调度, 完成固定的逻辑。

注意:为了防止恶意的操作,一般模板方法都加上final关键字,不允许被覆写

抽象模板类

package com.muban;
/*
 * @Description: 请输入....
 * @Author: 麦子
 * @Date: 2020-04-11 11:26:55
 * @LastEditTime: 2020-04-11 11:28:04
 * @LastEditors: 麦子
 */

public abstract class AbstractClass {

    // 基本方法
    protected abstract void doSomething();

    // 基本方法
    protected abstract void doAnything();

    // 模板方法
    public void templateMethod() {
        /* * 调用基本方法,完成相关的逻辑 */ 
        this.doAnything();
        this.doSomething();
    }

}

注意:抽象模板中的基本方法尽量设计为protected类型,符合迪米特法则,不需要暴露 的属性或方法尽量不要设置为protected类型。实现类若非必要,尽量不要扩大父类中的访问 权限。

优点

● 封装不变部分,扩展可变部分

把认为是不变部分的算法封装到父类实现,而可变部分的则可以通过继承来继续扩展。 在悍马模型例子中,是不是就非常容易扩展?例如增加一个H3型号的悍马模型,很容易 呀,增加一个子类,实现父类的基本方法就可以了。

● 提取公共部分代码,便于维护

我们例子中刚刚走过的弯路就是最好的证明,如果我们不抽取到父类中,任由这种散乱 的代码发生,想想后果是什么样子?维护人员为了修正一个缺陷,需要到处查找类似的代 码!

● 行为由父类控制,子类实现

基本方法是由子类实现的,因此子类可以通过扩展的方式增加相应的功能,符合开闭原 则。

缺点

按照我们的设计习惯,抽象类负责声明最抽象、最一般的事物属性和方法,实现类完成 具体的事物属性和方法。但是模板方法模式却颠倒了,抽象类定义了部分抽象方法,由子类 实现,子类执行的结果影响了父类的结果,也就是子类对父类产生了影响,这在复杂的项目 中,会带来代码阅读的难度,而且也会让新手产生不适感。

使用场景

● 多个子类有公有的方法,并且逻辑基本相同时。

● 重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个 子类实现。

● 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通 过钩子函数(见“模板方法模式的扩展”)约束其行为。

其实到这里可以更多的看到这个模式更多的就是一种抽象类的一种灵活封装和用法。

代码演示

package com.muban;
/*
 * @Description: 请输入....
 * @Author: 麦子
 * @Date: 2020-04-11 11:26:55
 * @LastEditTime: 2020-04-11 11:42:32
 * @LastEditors: 麦子
 */

public abstract class AbstractClass {

    // 基本方法
    protected abstract void doSomething();

    // 基本方法
    protected abstract void doAnything();

    // 模板方法
    public final void templateMethod() {
        /* * 调用基本方法,完成相关的逻辑 */
        if (this.check()) {
            this.doAnything();
            this.doSomething();
        }else{
            System.out.println("子类 重写 check ");
        }
    }

    protected boolean check() {
        return true;
    }

}
package com.muban;
/*
 * @Description: 请输入....
 * @Author: 麦子
 * @Date: 2020-04-11 11:33:50
 * @LastEditTime: 2020-04-11 11:46:50
 * @LastEditors: 麦子
 */

public class Car extends AbstractClass{

    @Override
    protected void doAnything() {
        
          System.out.println("do anything");
    }

    @Override
    protected void doSomething() {
         System.out.println("do something");
    }

    @Override
    protected boolean check() {
         return false;
    }
    

    public static void main(final String[] args) {
        final Car car = new Car();
         car.templateMethod();
    }

    
}

运行结果

子类 重写 check 

注意

需要注意, 在多个抽象方法组合的地方, 我们需要用final关键字,防止后面的子类进行方法的覆盖,这个方法就是所有的方法组合和骨架。

「真诚赞赏,手留余香」

真诚赞赏,手留余香

使用微信扫描二维码完成支付