设计模式学习系列:模板方法模式的学习

前言

最近在研究《设计模式之禅》,本篇设计模式学习系列主要是记录自己对设计模式的理解和应用。本篇博文主要是针对模板方法模式的解读及个人的理解,并会展示部分源代码给大家看。

环境

软件 版本
JDK 1.8

正文

定义

Define the skeleton of an algorithm in an operation,deferring some steps tosubclasses.Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.(在操作中定义算法的框架,将某些步骤延迟到子类。TemplateMethod使子类在不更改算法结构的情况下重新定义算法的某些步骤。)

说明

定义说得比较清楚,当我们有这样一个需求:我们已经知道了框架层次的处理过程,但是对于框架内部的各个具体实现是不清楚的。这个时候,我们就可以使用模板方法模式。我们可以定义这样一个抽象类,定义各个需要子类处理的函数,但是框架的整体处理方法是单独出来,不容许子类进行修改的。然后继承该抽象类的子类,只需要实现对应的方法即可,而不需要知道方法什么时候会被调用。或许说得比较抽象,接下来,我会展示一个例子给大家看。

例子

需求

上级给了一个需求,说要写一个后台程序,同时也说明了这个后台程序是准备做成顶级后台项目提供给大家用的,要求尽可能通用、简洁明了。

思路

接到这样一个需求,我们就得考虑一下,我们具体的应用场景是什么。对于后台程序来说,一般都有几个步骤:初始化、启动处理线程、处理程序、结束程序。对于这几个步骤,一般是通用的。而且,作为顶级项目,是需要设定好整体的处理流程的。而不能后台A先启动程序,然后再初始化,而后台B是先处理程序,然后再初始化。这样就有点乱套了。所以,针对需求,我们可以整理出来以下几点:

  1. 整体流程是固定的,可以接受微调;
  2. 具体实现的程序是未知的

看以上两点,是不是觉得,很符合模板方法模式的定义。

设计

由需求,我定义了DealProcess类,其中定义了initstartprocessendstartProcess方法。其中initstartprocessend是抽象方法,而startProcess方法是定义了final,不容许子类修改的。另外,为了演示的方便,我定义了两个具体实现类:DealMsgProcessDealBookProcess类。这里要说明的一点就是定义了isInit变量,主要是有些方法是不需要初始化的,所以设置这一个变量,也可以说是钩子,即由外部传参改变了内部运行规则。具体的类图如下,请各位查看:
在这里插入图片描述

show the code

接下来,我会把几个类的代码贴出来,供大家参考。因为是演示功能,所以里面都只是文本输出来替代具体的功能实现。

DealProcess 类代码

@Slf4j
@Setter
public abstract class DealProcess {
    /**
     * 是否需要初始化
     */
    protected Boolean isInit = true;

    /**
     * 初始化
     */
    protected abstract void init();

    /**
     * 启动
     */
    protected abstract void start();

    /**
     * 过程处理
     * @return 处理是否成功
     */
    protected abstract Boolean process();

    /**
     * 结束
     */
    protected abstract void end();

    /**
     * 启动过程,不可修改
     */
    public final void startProcess() {
        if (isInit) {
            log.info("开始-初始化");
            init();
        }else{
            log.info("该程序无需初始化");
        }
        log.info("########################################");
        log.info("启动-处理过程");
        start();
        log.info("########################################");
        log.info("开始-进行过程处理");
        Boolean resultStatus = process();
        if (resultStatus) {
            log.info("过程处理成功");
        }else{
            log.error("过程处理失败,请解决");
        }
        log.info("########################################");
        log.info("结束-处理过程");
        end();
    }
}

DealBookProcess 类代码

@Slf4j
public class DealBookProcess extends DealProcess {
    public DealBookProcess() {
        this.setIsInit(false);
    }

    /**
     * 初始化
     */
    @Override
    protected void init() {
        log.info("无需初始化");
    }

    /**
     * 启动
     */
    @Override
    protected void start() {
        log.info("启动-图书读取线程");
    }

    /**
     * 过程处理
     *
     * @return 处理是否成功
     */
    @Override
    protected Boolean process() {
        log.info("开始图书读取");
        log.info("图书读取中");
        log.info("图书读取完毕");

        return true;
    }

    /**
     * 结束
     */
    @Override
    protected void end() {
        log.info("关闭图书读取线程");
    }
}

DealMsgProcess 类代码

@Slf4j
public class DealMsgProcess extends DealProcess {
    public DealMsgProcess() {
        this.setIsInit(true);
    }

    /**
     * 初始化
     */
    @Override
    protected void init() {
        log.info("初始化-消息接收线程");
    }

    /**
     * 启动
     */
    @Override
    protected void start() {
        log.info("开始启动-消息接收线程");
    }

    /**
     * 过程处理
     *
     * @return 处理是否成功
     */
    @Override
    protected Boolean process() {
        log.info("开始启动-处理过程");
        log.info("消息清洗过程完毕,耗时1秒");

        return true;
    }

    /**
     * 结束
     */
    @Override
    protected void end() {
        log.info("关闭-消息接收线程");
    }
}

Client类代码

@Slf4j
public class Client {
    public static void main(String[] args) {
        DealProcess bookProcess = new DealBookProcess();
        bookProcess.startProcess();

        log.info("----------------------------------------");
        DealProcess msgProcess = new DealMsgProcess();
        msgProcess.startProcess();
    }
}

以上为全部的代码了。功能比较简单,所以代码也比较简单。主要是展示模板方法的理念。

测试输出

22:59:53.156 [main] INFO DealProcess - 该程序无需初始化
22:59:53.170 [main] INFO DealProcess - ########################################
22:59:53.170 [main] INFO DealProcess - 启动-处理过程
22:59:53.170 [main] INFO DealBookProcess - 启动-图书读取线程
22:59:53.170 [main] INFO DealProcess - ########################################
22:59:53.170 [main] INFO DealProcess - 开始-进行过程处理
22:59:53.170 [main] INFO DealBookProcess - 开始图书读取
22:59:53.170 [main] INFO DealBookProcess - 图书读取中
22:59:53.171 [main] INFO DealBookProcess - 图书读取完毕
22:59:53.172 [main] INFO DealProcess - 过程处理成功
22:59:53.172 [main] INFO DealProcess - ########################################
22:59:53.172 [main] INFO DealProcess - 结束-处理过程
22:59:53.172 [main] INFO DealBookProcess - 关闭图书读取线程
22:59:53.172 [main] INFO Client - ----------------------------------------
22:59:53.172 [main] INFO DealProcess - 开始-初始化
22:59:53.172 [main] INFO DealMsgProcess - 初始化-消息接收线程
22:59:53.172 [main] INFO DealProcess - ########################################
22:59:53.172 [main] INFO DealProcess - 启动-处理过程
22:59:53.172 [main] INFO DealMsgProcess - 开始启动-消息接收线程
22:59:53.172 [main] INFO DealProcess - ########################################
22:59:53.172 [main] INFO DealProcess - 开始-进行过程处理
22:59:53.172 [main] INFO DealMsgProcess - 开始启动-处理过程
22:59:53.172 [main] INFO DealMsgProcess - 消息清洗过程完毕,耗时1秒
22:59:53.172 [main] INFO DealProcess - 过程处理成功
22:59:53.173 [main] INFO DealProcess - ########################################
22:59:53.173 [main] INFO DealProcess - 结束-处理过程
22:59:53.173 [main] INFO DealMsgProcess - 关闭-消息接收线程

优点

  1. 封装不可变部分,扩展可变部分;
  2. 行为由父类控制,而子类来实现具体行为。

缺点

子类来影响了父类,假如子类出现了问题,则父类也会出现问题。

总结

本文学习了模板方法设计模式,了解了其定义及理念,并给出了具体的代码实现。而实际的项目开发中,需要结合实际进行开发,而不能硬搬硬套。

随缘求赞

如果我的文章对大家产生了帮忙,可以在文章底部点个赞或者收藏;
如果有好的讨论,可以留言;
如果想继续查看我以后的文章,可以左上角点击关注
可以扫描以下二维码,关注我的公众号:枫夜之求索阁,查看我最新的分享!
在这里插入图片描述
拜拜

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章