設計模式學習系列:模板方法模式的學習

前言

最近在研究《設計模式之禪》,本篇設計模式學習系列主要是記錄自己對設計模式的理解和應用。本篇博文主要是針對模板方法模式的解讀及個人的理解,並會展示部分源代碼給大家看。

環境

軟件 版本
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. 行爲由父類控制,而子類來實現具體行爲。

缺點

子類來影響了父類,假如子類出現了問題,則父類也會出現問題。

總結

本文學習了模板方法設計模式,瞭解了其定義及理念,並給出了具體的代碼實現。而實際的項目開發中,需要結合實際進行開發,而不能硬搬硬套。

隨緣求贊

如果我的文章對大家產生了幫忙,可以在文章底部點個贊或者收藏;
如果有好的討論,可以留言;
如果想繼續查看我以後的文章,可以左上角點擊關注
可以掃描以下二維碼,關注我的公衆號:楓夜之求索閣,查看我最新的分享!
在這裏插入圖片描述
拜拜

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