设计模式~模板方法模式

105 阅读3分钟

1. 定义

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

2. UML类图

image.png

  • AbsTemplate:抽象类,定义了一套算法框架
  • ConcreteImplA:具体实现类A
  • ConcreteImplB:具体实现类B

3. 使用场景

  • 各子类中有公共的方法,并且逻辑基本相同时,可集中到一个公共父类中以避免代码重复。
  • 面对重要复杂的算法,可以把核心算法设计为模版方法,周边相关细节功能则由各个子类实现。
  • 代码重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为

4. 简单实现

  • 需求:模板方法实际上就是封装一个固定的流程,例如开机电脑可以简单的概括为:
    • 启动电源
    • 检查硬件环境
    • 加载操作系统
    • 用户通过输入密码等方式进入系统
  • 首先构造一个包含这些模板方法流程的抽象类
/**
 * 启动计算机的抽象模板
 *
 * @author BTPJ  2022/6/28
 */
public abstract class AbsComputer {

    protected void openPower() {
        System.out.println("打开计算机电源");
    }

    protected void checkHardware() {
        System.out.println("计算机硬件检查");
    }

    protected void loadOS() {
        System.out.println("加载windows/mac os操作系统");
    }

    protected void login() {
        System.out.println("默认未设置密码直接登录");
    }

    /**
     * 开启计算机,规定计算机的启动模板
     */
    public final void startup() {
        System.out.println("-----------计算机开机start");
        openPower();
        checkHardware();
        loadOS();
        login();
        System.out.println("-----------计算机开机end");
    }
}
  • 普通电脑的启动流程(大多数只需要在默认状态下加入用户密码即可)
/**
 * 通常用户的电脑
 *
 * @author BTPJ  2022/6/28
 */
public class CommonComputer extends AbsComputer {

    @Override
    protected void login() {
        System.out.println("通常用户设置了密码,只需要正确输入密码进入系统");
    }
}
  • 军用级的电脑启动流程需要加入硬件级的防火墙,专用的操作系统以及更高级的登录方式
/**
 * 军用级别的电脑
 *
 * @author BTPJ  2022/6/28
 */
public class MilitaryComputer extends AbsComputer {

    @Override
    protected void checkHardware() {
        System.out.println("检查硬件防火墙");
    }

    @Override
    protected void loadOS() {
        System.out.println("加载军用级专用操作系统");
    }

    @Override
    protected void login() {
        System.out.println("采用指纹密码的方式进入系统");
    }
}
  • main方法调用类
/**
 * 调用类
 *
 * @author BTPJ  2022/6/28
 */
public class TemplateMain {
    public static void main(String[] args) {
        CommonComputer commonComputer = new CommonComputer();
        commonComputer.startup();

        System.out.println("-----------------------------------------");

        MilitaryComputer militaryComputer = new MilitaryComputer();
        militaryComputer.startup();
    }
}
  • 运行结果
-----------计算机开机start
打开计算机电源
计算机硬件检查
加载windows/mac os操作系统
通常用户设置了密码,只需要正确输入密码进入系统
-----------计算机开机end
-----------------------------------------
-----------计算机开机start
打开计算机电源
检查硬件防火墙
加载军用级专用操作系统
采用指纹密码的方式进入系统
-----------计算机开机end

5. 源码中的使用场景

  • Android的AsyncTask使用模板方法模式封装了onPreExcute、doInBackground、onPostExecute模板方法
  • Android生命周期函数等

6. 优缺点

  • 优点:
    • 封装不变的行为搬移到超类,去除了子类中的重复代码,可变部分可扩展
    • 提取公共代码,便于维护
  • 缺点:
    • 每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象