設計之美——模板方法模式

来源:http://www.cnblogs.com/mxlandxt/archive/2017/05/22/6888893.html
-Advertisement-
Play Games

一、什麼是模板方法模式 概念:定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。 通俗的講,模板方法模式是通過把不變行為搬到超類,去除子類裡面的重覆代碼提現它的優勢,它提供了一個很好的代碼復用平臺。當不可變和可變的方法在子類 ...


一、什麼是模板方法模式

  概念:定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。

  通俗的講,模板方法模式是通過把不變行為搬到超類,去除子類裡面的重覆代碼提現它的優勢,它提供了一個很好的代碼復用平臺。當不可變和可變的方法在子類中混合在一起的時候,不變的方法就會在子類中多次出現,這樣如果摸個方法需要修改則需要修改很多個,雖然這個這個問題在設計之初就應該想好。這個時候模板方法模式就起到了作用了,通過模板方法模式把這些重覆出現的方法搬到單一的地方,這樣就可以幫助子類擺脫重覆不變的糾纏。

  舉個好懂的例子,小時候筆者家裡窮,在農村上小學的時候考試都是每個學生手抄試卷,因為那個時候學校還沒有試卷印刷。全班五十多個學生每個學生都要重覆抄一遍黑板的試卷,並且像筆者這樣的近視眼很容易就抄錯了,8抄成3,7抄成1等到,然後明明做對了但是分數就是不高,導致筆者一直是全班倒數。這就是個很嚴重的重覆不可變的問題,現在條件好了不少,學生不需要抄試卷,試卷印刷就解決了這個重覆抄試卷的問題。模板方法也是類似。

二、模式對比

1、抄試卷模式

筆者就以抄試卷模式為名來闡述重覆不變帶來的不便,下麵會對該模式進行改進。

學生甲抄的試卷

public class TestPaperA {
    //試卷第一題
    public void testQuestion1(){
        System.out.println("小龍女是楊過的什麼親戚?() A.小姨媽  B.大姨媽  C.姑媽  D.舅媽");
        System.out.println("答案:C");
    }
    
    //試卷第二題
    public void testQuestion2(){
        System.out.println("全真教的首任掌門是誰?A.周伯通 B.歐陽鋒 C.王重陽 D.西門吹牛");
        System.out.println("答案:C");
    }
    
    //試卷第三題
    public void testQuestion3(){
        System.out.println("《天龍八部》中被封為南院大王的大俠是誰?A.段譽 B.喬峰 C.慕容復 D.段智興");
        System.out.println("答案:B");
    }
}

學生乙抄的試卷

public class TestPaperB {
    //試卷第一題
    public void testQuestion1(){
        System.out.println("小龍女是楊過的什麼親戚?() A.小姨媽  B.大姨媽  C.姑媽  D.舅媽");
        System.out.println("答案:A");
    }
    
    //試卷第二題
    public void testQuestion2(){
        System.out.println("全真教的首任掌門是誰?A.周伯通 B.歐陽鋒 C.王重陽 D.西門吹牛");
        System.out.println("答案:C");
    }
    
    //試卷第三題
    public void testQuestion3(){
        System.out.println("《天龍八部》中被封為南院大王的大俠是誰?A.段譽 B.喬峰 C.慕容復 D.段智興");
        System.out.println("答案:D");
    }
}

客戶端代碼

public class ShowAnswer {

    public static void main(String[] args) {
        System.out.println("學生甲的試卷");
        TestPaperA stuA = new TestPaperA();
        stuA.testQuestion1();
        stuA.testQuestion2();
        stuA.testQuestion3();
        System.out.println("學生乙的試卷");
        TestPaperB stuB = new TestPaperB();
        stuB.testQuestion1();
        stuB.testQuestion2();
        stuB.testQuestion3();
    }

}

很容易發現上面兩個學生抄的試卷有很多重覆的地方,比如試卷的題目,輸出答案的方法,這些都在每個學生試卷類中混合在一起了,既不利於維護,也不利於瀏覽,下麵看一下模板方法模式是怎麼改進的。

2、模板方法模式

將每個學生試卷的重覆部分提取出來,題目,作答等等。

首先改造試卷類,將該類改為抽象類,在該類中我添加了三個抽象的方法用於子類實現,學生都是要作答的,但是答案不一樣,所以可以將作答的過程作為重覆不變的方法提取出來,代碼如下。

public abstract class TestPaper {
    //試卷第一題
    public void testQuestion1(){
        System.out.println("小龍女是楊過的什麼親戚?() A.小姨媽  B.大姨媽  C.姑媽  D.舅媽");
        System.out.println("答案:" + answer1());
    }
    
    //試卷第二題
    public void testQuestion2(){
        System.out.println("全真教的首任掌門是誰?A.周伯通 B.歐陽鋒 C.王重陽 D.西門吹牛");
        System.out.println("答案:" + answer2());
    }
    
    //試卷第三題
    public void testQuestion3(){
        System.out.println("《天龍八部》中被封為南院大王的大俠是誰?A.段譽 B.喬峰 C.慕容復 D.段智興");
        System.out.println("答案:" + answer3());
    }
    
    //這三個鉤子方法是給每個子類去實現,並返回答案的
    public abstract String answer1();
    public abstract String answer2();
    public abstract String answer3();
    
    //模板方法,考試的過程,定義基本的考試過程,子類回調
    public void exam(){
        testQuestion1();
        testQuestion2();
        testQuestion3();
    }
}

首先來看第一個學生的考試情況

public class TestPaperA extends TestPaper{

    @Override
    public String answer1() {
        return "A";
    }

    @Override
    public String answer2() {
        return "B";
    }

    @Override
    public String answer3() {
        return "D";
    }
    
}

其他學生的試卷可能答案不是一樣的,但是基本的答題過程就是一樣的,所以就不重覆寫了,下麵看下客戶端代碼。

public class ShowAnswer {

    public static void main(String[] args) {
        TestPaper testPaper = new TestPaperA();
        testPaper.exam();
    }

}

可以看待客戶端代碼也減輕了很多,這樣邏輯清晰,利於維護,優勢很明顯,下麵看下具體答題情況。

小龍女是楊過的什麼親戚?() A.小姨媽  B.大姨媽  C.姑媽  D.舅媽
答案:A
全真教的首任掌門是誰?A.周伯通 B.歐陽鋒 C.王重陽 D.西門吹牛
答案:B
《天龍八部》中被封為南院大王的大俠是誰?A.段譽 B.喬峰 C.慕容復 D.段智興
答案:D

3、模板方法模式的基本結構

AbstractClass是一個抽象類,其實就是一個抽象模板,定義並實現了一個模板方法。這個模板方法一般是一個具體的實現,他給出了一些邏輯的骨架,而邏輯的組成在相應的抽象類中,推遲到了子類實現。代碼如下

public abstract class AbstractClass {

    //一些抽象行為,可以理解為重覆不變的方法,提取到抽象類
    public abstract void primitiveOperation1();
    public abstract void primitiveOperation2();
    
    //模板方法,給出了具體邏輯的骨架,而邏輯的組成是一些相應的抽象操作,他們都推遲到子類實現
    public void templateMothed(){
        primitiveOperation1();
        primitiveOperation2();
    }
    
}

ConcreteClass,實現父類所定義的一個或多個抽象方法。每一個AbstractClass都可以有一個或者多個ConcreteClass與之對應,而每一個ConcreteClass都可以給出這些抽象方法(也就是骨架的組成步驟)的不同實現,從而得到的實現都不同。

public class ConcreteClassA extends AbstractClass{

    @Override
    public void primitiveOperation1() {
        System.out.println("子類A的操作1");
    }

    @Override
    public void primitiveOperation2() {
        System.out.println("子類A的操作2");
    }

}
public class ConcreteClassB extends AbstractClass{

    @Override
    public void primitiveOperation1() {
        System.out.println("子類B的操作1");
    }

    @Override
    public void primitiveOperation2() {
        System.out.println("子類B的操作2");
    }

}

上面定義了兩個具體的實現,更多的實現其實都是一致的,這裡就不多多說了。下麵看下客戶端代碼

public class Show {

    public static void main(String[] args) {
        AbstractClass c;
        c = new ConcreteClassA();
        c.templateMothed();
        c = new ConcreteClassB();
        c.templateMothed();
    }
    
}

輸入如下

子類A的操作1
子類A的操作2
子類B的操作1
子類B的操作2

4、UML圖

三、總結

  模板方法模式就是為了將重覆不變的代碼提取到一個抽象類中。當我們要完成在某一細節層次一致的一個過程或一系列步驟,但其個別步驟在更詳細的層次上的實現可能不同時,我們通常考慮用模板方法模式來處理。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ★☆ 輸入文件:2015message.in 輸出文件:2015message.out 簡單對比 時間限制:1 s 記憶體限制:256 MB 【題目描述】 有n個同學(編號為1到n)正在玩一個信息傳遞的游戲。在游戲里每人都有一個固定的信息傳遞對象,其中,編號為i的同學的信息傳遞對象是編號為Ti同學。 ...
  • 今天繼續函數的講解: 目錄: 1.函數對象 2.函數嵌套 3.名稱空間和作用域 4.閉包 5.裝飾器 6.迭代器 7.生成器 8.內置函數 第一部分:函數對象 在python中,一切皆對象,想int,str,list,dict,tuple等等,所以函數也不例外,對象都具有屬性。作為對象,它可以賦值給 ...
  • 最近工作中要用到搜索引擎,由於目前用的搜索引擎是LeanCloud 提供的 ,不太好用,不支持範圍等搜索,而且每天還收費30元,請求次數也有限制。基於這些原因,我們只好在自己的伺服器上部署搜索引擎了。 經過一番調研結合我們自身的技術,選擇使用Elasticsearch,下麵介紹Elasticsear ...
  • xml即可擴展標記語言,它可以用來標記數據、定義數據類型,是一種允許用戶對自己的標記語言進行定義的源語言。從結構上,很像HTML超文本標記語言。但他們被設計的目的是不同的,超文本標記語言被設計用來顯示數據,其焦點是數據的外觀。它被設計用來傳輸和存儲數據,其焦點是數據的內容。那麼Python是如何處理 ...
  • 設計模式三—抽象工廠模式 一、定義 抽象工廠模式是工廠方法模式的進一步抽象。如果產品簇中只有一種產品,則退化為工廠方法模式。 二、原理圖 三、代碼實例 * 蘋果和土豆是園丁1的傑作 * 葡萄和西紅柿是園丁2的傑作 1、Fruit.java 2、Apple.java 3、Grape.java 4、Ve ...
  • 設計模式二—工廠方法模式 一、工廠方法模式優點 良好的封裝性 優秀的可擴展性 屏蔽產品類 典型的解耦架構 二、實例 三、實例代碼 1、Fruit.java public interface Fruit { /* * 生長 * 收穫 * 栽種 */ public void grow(); public ...
  • 1 [root@ ~/learn_code/design_pattern/19_order]$ cat order.cpp 2 #include 3 #include 4 #include 5 #include 6 #include 7 8 using namespace std; 9 10 cla... ...
  • 參考: http://www.cnblogs.com/jiese/p/3164940.html http://design-patterns.readthedocs.io/zh_CN/latest/structural_patterns/bridge.html ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...