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

来源: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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...