談笑間學會模板方法模式

1 背景

某天早上,Skr郎正在一邊悠哉的吃着加了三跟烤腸的手抓餅,一邊悠閒地逛着論壇,看着沙雕網友的帖子,Skr郎會心一笑,正欲給沙雕帖子點贊,郵件忽的彈出,Skr郎慢悠悠的打開郵件

            公司關於XXXX年XX月XX日生產事故通報批評
    在XXXX年XX月XX日版本上線後,由於GP6(軟件工程師)與TP9(測試工程師)的個人原因,導致上線功能出現異常,客戶投訴,對此予以通報批評!

    扣除XX月績效........
    .......
    .......
                                        XXXX年XX月XX日      

Skr郎看着旁邊的臉色很差GP6問道:什麼生產事故?怎麼都通報了?

GP6: 哎,原有的導出文件,統一修改表頭與表尾的內容格式,需要改動的地方太多了,有幾個處漏改了,你也看一下,前世之事,後事之師啊!

Skr: 好的,我要吸取這次教訓,避免以後出現同樣的錯誤!

2 事故代碼

/**
 * 交易Service
 *
 * @author gp6
 * @date 2020/3/20
 */
public class TradeService {

    /**
     * 交易表單導出
     *
     * @param storeName 店鋪名稱
     */
    public void exportTradeData(String storeName) {
        System.out.println("表頭:Skr-" + storeName);
        System.out.println("交易數據");
        System.out.println("表尾:當天日期");
    }
}

----------------------------------------------------------------------------------------------------

/**
* 訂單Service
*
* @author gp6
* @date 2020/3/20
*/
public class OrderService {

    /**
     * 訂單表單導出
     *
     * @param storeName 店鋪名稱
     */
    public  void exportOrderData(String storeName) {
        System.out.println("表頭:Skr-" + storeName);
        System.out.println("訂單數據");
        System.out.println("表尾:當天日期");
    }
}

----------------------------------------------------------------------------------------------------

/**
 * 粉絲Service
 *
 * @author gp6
 * @date 2020/3/20
 */
public class FansService {

    /**
     * 新增粉絲表單導出
     *
     * @param storeName 店鋪名稱
     */
    public void exportAddFansData(String storeName) {
        System.out.println("表頭:Skr-" + storeName);
        System.out.println("新增粉絲數據");
        System.out.println("表尾:當天日期");
    }
}

----------------------------------------------------------------------------------------------------

/**
 * 測試模板方法
 *
 * @author gp6
 * @date 2020/3/20
 */
public class TestTemplate {

    public static void main(String[] args) {
        // 1 : 交易表單導出
        TradeService tradeService = new TradeService();
        tradeService.exportTradeData("SM旗艦店");

        // 2 : 訂單表單導出
        OrderService orderService = new OrderService();
        orderService.exportOrderData("SM旗艦店");

         // 3 : 新增粉絲表單導出
        FansService fansService = new FansService();
        fansService.exportAddFansData("SM旗艦店");

        // 4 : 等等等等很多個
    }
}

GP6: 本次的需求就是將每個導出文件表頭與表尾的內容格式進行統一修改,結果我有幾個地方的導出漏掉了,因爲需求簡單,測試只對其中幾個進行測試,沒有問題,他就沒有進行全部測試…

Skr郎看着代碼,說道: 還好這次沒有涉及到金錢損失,要是你這次改動的是涉及金錢交易的邏輯,你估計就要直接捲鋪蓋滾蛋…

GP6: 哎,你就別調侃我了,你說這麼多地方,我哪能找全啊,

Skr: 既然他們表頭表尾都是一樣的你爲什麼不把通用的邏輯抽取出來?這樣的話,下次如果再修改表頭與表尾的內容格式,是不是隻需改動抽取出來的公用邏輯就行!

GP6: 有道理哦!那我把通用邏輯抽到一個工具類吧

Skr: 敲代碼之前要先想一想"高內聚,低耦合",通用邏輯抽取,用模板方法模式不是更符合"高內聚"嗎

3 模板方法模式

定義:
	定義一個操作中的算法骨架,而將算法的一些步驟延遲到子類中,使得子類可以不改變該算法結構的情況下重定義該算法的某些特定步驟

看了模板方法模式的定義,是不是很符合這種場景

定義一個操作中的算法骨架(表頭,獲取XX數據,表尾),而將算法的一些步驟(獲取XX數據)延遲到子類中,使得子類可以不改變該算法結構的情況下重定義該算法的某些特定步驟(獲取的數據不同)

簡直完美,Skr郎沾沾自喜

/**
 * 模板方法的核心(定義一個操作中的算法骨架)
 *
 * @author gp6
 * @date 2020/3/20
 */
public abstract class AbstractTemplate {

    /**
     * 導出數據
     *
     * @param storeName 店鋪名稱
     */
    public void exportData(String storeName) {
        // 通用邏輯--表頭
        header(storeName);

        // 獲取不同的數據
        getData();

        // 通用邏輯--表尾
        end();
    }

    /**
     * 表頭
     *
     * @param storeName 店鋪名稱
     */
    private void header(String storeName) {
        System.out.println("表頭:Skr-" + storeName);
    }

    /**
     * 表尾
     */
    private void end() {
        System.out.println("當天日期");
    }

    /**
     * 獲取數據(算法的一些步驟(獲取XX數據)延遲到子類)
     */
    public abstract void getData();
}


/**
 * 交易Service
 *
 * @author gp6
 * @date 2020/3/20
 */
public class TradeService extends AbstractTemplate{

    /**
     * 獲取交易數據
     */
    @Override
    public void getData() {
        System.out.println("交易數據");
    }
}

/**
* 訂單Service
*
* @author gp6
* @date 2020/3/20
*/
public class OrderService  extends AbstractTemplate{

    /**
     * 獲取訂單數據
     */
    @Override
    public void getData() {
        System.out.println("訂單數據");
    }
}

/**
 * 粉絲Service
 *
 * @author gp6
 * @date 2020/3/20
 */
public class FansService extends AbstractTemplate{

    /**
     * 獲取新增粉絲數據
     */
    @Override
    public void getData() {
        System.out.println("新增粉絲數據");
    }
}

/**
 * 測試模板方法
 *
 * @author gp6
 * @date 2020/3/20
 */
public class TestTemplate {

    public static void main(String[] args) {
        // 1 : 交易表單導出
        TradeService tradeService = new TradeService();
        tradeService.exportData("SM旗艦店");

        // 2 : 訂單表單導出
        OrderService orderService = new OrderService();
        orderService.exportData("SM旗艦店");

        // 3 : 新增粉絲表單導出
        FansService fansService = new FansService();
        fansService.exportData("SM旗艦店");
    }
}

此時如果要修改表頭或表尾內容格式,只需在AbstractTemplate此類中修改即可

Skr郎寫到此處,心滿意足的點點頭,心中評價道:這段代碼,邏輯嚴謹,註釋清晰,優雅中透露着灑脫,灑脫中透露着不羈,真是"此碼只應天上有,人間難得幾回尋!"
呀! 想不到我作詩的功夫也如此深厚,哎,如此完美的男人,別人只能羨慕嫉妒恨!

4 模板方法模式類圖

模板方法模式類圖

類圖中Man/Woman相當於文章中的OrderService/FansService/TradeService

allShop()相當於文章中的exportData()

go()相當於文章中的header()/end()

shop()相當於文章中的exportData()

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