【行为模式】模板方法模式

143 阅读4分钟

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

概述

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

生活案例

上小学的时候,老师买了课外书籍。由于只有老师有这个书,所以布置作业的形式就是科代表把题目抄在黑板上,每个人拿本子抄。就像下面这样:

随着社会进步,现在的小学生早已脱离苦海,现在作业不用手抄,直接复印。从上文可以看出时代在进步,从手抄到复印。二者区别在于复印的每一份必然是一样的,手抄的就可能出问题,并且复印的效率是高于手抄的! 不管是手抄还是复印,最终目的是为了做题。100个人做100份题,题目都是一样的,唯一不同的就是每个人的答案不同,程序开发中也存在类似的问题,这个时候我们可以定义一套算法骨架(试卷),然后由不同的实现类(学生)去实现不同的逻辑(答案)。 ​

实际场景

《深入设计模式》场景是第一次迭代做Doc文档数据导入数据库,第二次迭代是CSV导入数据库,第三次是PDF导入数据库。图中三个mine方法只有加粗的地方是不一样,一般情况下我们会将重复的步骤向上抽取,不同的地方留给子类自己实现。这里一样的部分就像试卷,不一样的就像每个学生填写的答案。  ​

代码示例

抽象基类是一个试卷类,该类实现了两套试卷(骨架),两个骨架分别对应两个子类。写两套骨架是因为想告诉大家不要有局限性思维,基类里是可以有很多套骨架(试卷)的,具体根据实际场景来。

抽象基类

/**
 * 试卷基类
 *
 * @author evader
 * @date 2021-09-01 06:55
 */
public abstract class AbstractExam {

    /**
     * 模板方法一(数学试题)
     */
    public void templateMethodOne() {
        System.out.println("第一题:1 * 1 = ?");
        System.out.println("答案是:" + answerOne());

        System.out.println("第二题:1 + 1 = ?");
        System.out.println("答案是:" + answerTwo());

        System.out.println("第三题:1 - 1 = ?");
        System.out.println("答案是:" + answerThree());
    }

    /**
     * 模板方法二(Java试题)
     */
    public void templateMethodTwo() {
        System.out.println("第一题:Java三大特性是什么?");
        System.out.println("答案是:" + answerOne());

        System.out.println("第二题:谈谈你对抽象类与接口的理解。");
        System.out.println("答案是:" + answerTwo());

        System.out.println("第三题:Object类是超类吗?");
        System.out.println("答案是:" + answerThree());
    }

    /**
     * 答案一
     * 方法可以添加返回值,基类声明变量,通过构造方法注入即可
     */
    abstract String answerOne();

    /**
     * 答案二
     */
    abstract String answerTwo();

    /**
     * 答案三
     */
    abstract String answerThree();
}

具体子类一

public class StudentOne extends AbstractExam{
    @Override
    String answerOne() {
        return "1";
    }

    @Override
    String answerTwo() {
        return "1";
    }

    @Override
    String answerThree() {
        return "1";
    }
}

具体子类二

public class StudentTwo extends AbstractExam{

    @Override
    String answerOne() {
        return "2";
    }

    @Override
    String answerTwo() {
        return "2";
    }

    @Override
    String answerThree() {
        return "2";
    }
}

具体子类三

public class JavaStudentOne extends AbstractExam{
    @Override
    String answerOne() {
        return "封装,继承,多态";
    }

    @Override
    String answerTwo() {
        return "抽象类给同行用的,接口给外行用的";
    }

    @Override
    String answerThree() {
        return "是";
    }
}

具体子类四

public class JavaStudentTwo extends AbstractExam{
    @Override
    String answerOne() {
        return "不会";
    }

    @Override
    String answerTwo() {
        return "不会";
    }

    @Override
    String answerThree() {
        return "不会";
    }
}

测试结果

动图封面

UML类图

总结

模板方法模式封装了不变的部分,扩展可变的部分。这种设计思想是非常符合开闭原则的,并且提高了程序的利用率。当然它也有一定的缺点,我认为最大的缺陷是基类添加一个新的抽象方法,那么已经实现的所有子类都必须修改。

扩展:工厂方法模式,策略模式与模板方法模式

  • 工厂方法模式可以理解为特殊的模板方法模式,这种模板方法模式的算法骨架是一样的,不需要子类来补充。
  • 策略模式与模板方法异曲同工之妙,只不过策略模式是在运行过程中改变算法逻辑(对象层次),而模板方法从一开始就确定了,是静态的(类层次)