前言

今天我们来分享另一款设计模式,相比于前面的设计模式,这种设计模式,显得更加简单,只有两个类,一个是模板方法抽象类,一个是基层实现类。

它更像是一种自上而下的模式,有些类似于公司决策,由高层指定相关流程,由下层负责具体细则实现,这种设计模式的好处是,当具体细则发生变更时,只需要改动具体实现的细则即可,而上层流程是不需要发生变化的,同样的,如果上层流程发生变动,只需要调整生词流程执行过程即可,而不需要底层做任何更改,这样就可以有效实现上层业务和底层实现之间的有效解耦,是不是很有效呢?

所以说,模板方法模式本质上就是对IPO的代码实现而已,由高层确定I/O标准,并指定具体实施的步骤(process),由底层负责具体实现细则,下面我们就来看下具体实现过程。

模板方法

模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

设计模式详解——模板方法模式_子类

要点

  • 模板方法的抽象类可以定义具体方法、抽象方法和钩子,其中抽象方法由子类实现
  • 钩子是一种方法,它在抽象类中不做事,或者只做默认的事情,子类可以选择要不要覆盖它
  • 为了防止子类改变模板方法中的算法,可以将模板方法声明为final
  • 好莱坞原则(别找我,我会找你)告诉我们,将决策权放在高层模板中,以便于决定如何以及何时调用低层模块

示例

下面我们就来通过日常生活中的一个示例来说明下模板方法的应用场景。这是我们针对经常玩的两款游戏做的一个模拟,希望通过这个示例,能够帮助大家认识和理解模板方法。

模板方法抽象类

首先我们定义了一个抽象类,这是一个市面上所有游戏都会有的一个主体流程:资源初始化、开始游戏、游戏结束,同时定义了一个不可以被覆写的方法(final修饰的方法子类是无法覆写的),这样的好处是,抽象类的提供方(上层架构)可以控制流程的执行顺序:

public abstract class GameAbstract {
    /**
     * 初始化操作
     */
    abstract void initialize();

    /**
     * 开始游戏
     */
    abstract void startPlay();

    /**
     * 游戏结束
     */
    abstract void endPlay();

    /**
     * 模板
     */
    public final void play(){

        //初始化游戏
        initialize();

        //开始游戏
        startPlay();

        //结束游戏
        endPlay();
    }
}
基层实现

这里就是基层的实现(也就是服务提供方),下面是对王者荣耀这块游戏做的模拟:

public class GloryOfKingsGame extends GameAbstract{
    @Override
    public void initialize() {
        System.out.println("=================游戏初始化==================");
        System.out.println("初始化游戏数据");
        System.out.println("等待确认");
        System.out.println("加载游戏资源");
    }

    @Override
    public void startPlay() {
        System.out.println("=================开始游戏==================");
        System.out.println("敌人还有五秒到达战场……");
        System.out.println("First blood!  第一滴血");
        System.out.println("double kill!  双杀");
        System.out.println("triple kill!  三杀");
        System.out.println("Quadro  kill! 四杀");
        System.out.println("Penta kill! 五杀");
        System.out.println("Ace! 团灭");
        System.out.println("Unstoppable! 势不可挡");
        System.out.println("God like! 超神");
        System.out.println("Legendary! 传奇");
        System.out.println("shut down! 终结");
    }

    @Override
    public void endPlay() {
        System.out.println("=================游戏结束==================");
        System.out.println("victory! 赢了");
    }
}

运行结果如下:

设计模式详解——模板方法模式_子类_02

这里是对使命召唤进行的模拟,为了模拟这个游戏,我还专门玩了一把。我是比较喜欢射击类游戏的,这款游戏也算玩的比较多的:

public class MissionCallGame extends GameAbstract {
    @Override
    public void initialize() {
        System.out.println("=================游戏初始化==================");
        System.out.println("初始化游戏数据");
        System.out.println("等待确认");
        System.out.println("加载游戏资源");
    }

    @Override
    public void startPlay() {
        System.out.println("冲锋团队竞技!");
        System.out.println("我们领先了!");
        System.out.println("目标即将完成,请再坚持一下!");
        System.out.println("目我们赢了,一大赢,小心敌人反扑!");
    }

    @Override
    public void endPlay() {
        System.out.println("胜利");
    }
}

运行结果:

设计模式详解——模板方法模式_设计模式_03

好了,示例就展示这么多,因为整体内容也确实不难。不过,想必大家也已经从上面的示例中理解了模板方法的设计模式,以及它的应用场景。

对比

  • 策略模式和模板方法模式都是封装算法,前者用了组合方式,而后者用了继承方式
  • 工厂方法是模板方法的一种特殊版本

总结

模板方法设计模式的核心是,由上层控制流程,下层负责具体细则实现。而且从示例中我们也可以很清楚地看到,上层定义了一个不可覆写的方法来控制业务执行流程,同时暴露了三个子类必须要实现的抽象方法,这样就既可以实现上层和下层之间有效解耦,同时还能确保上层可以控制下层业务执行流程,也算是一种减少上下层代码之间互相侵入的一种有效模式吧!