設計模式——使用模板方法模式儘量減少重複相似的程式碼段

weixin_34208283發表於2017-07-18

引言

無論是現實生活還是實際開發中,我們常常會遇到一類相似的行為,他們都包含相似的基本操作和固定的流程,不同的是他們在不同的業務場景下,這些基本操作的具體實現有所不同,但是執行流程模式都是相同,當然最簡單的話我們針對不同的業務區實現對應的基本操作,但那是很low的,程式碼質量堪憂,明明是重複的程式碼就沒有必要存在了,模板方法模式就是解決這樣的問題,同時還可以讓後面接手的開發同學用最少的程式碼、最簡單的方式來複用並實現更多的業務。

一、模板方法概述

模板方法模式是一種類的行為型模式,在它的結構圖中只有類之間的繼承關係,沒有物件關聯關係,模板方法模式(Template Method Pattern)官方定義:定義一個操作中的演算法的框架,而將一些步驟延遲到子類中,使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。(Define the skeleton of an algorithm in an operation,deferring some steps to subclasses.Template
Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's
structure.)是不是很裝X,通俗來說模板方法模式本質僅僅是使用了Java的繼承機制,封裝幾個抽象方法和一個具體模板方法。模板方法模式中作為父類的抽象類叫做抽象模板AbstractClass,抽象模板中的基本方法儘量設計為protected型別,符合迪米特法則,不需要暴露的屬性或方法儘量不要設定為protected型別。實現類若非必要,儘量不要擴大父類中的訪問許可權;繼承抽象模板的就叫做具體模板,抽象模板中包含三種型別的方法: 基本方法模板方法鉤子方法(Hook Method)。

  • 基本方法——基本方法也叫做基本操作,是由子類實現的方法,並且在模板方法被呼叫。

  • 模板方法——核心方法,不允許子類重寫,所以都會加上final修飾符,可以有一個或幾個,一般是一個具體方法框架,按照固定的流程對基本方法的排程

  • 鉤子方法——為了讓模板方法的執行結果的更好地適應因外界條件改變。比如說銀行辦理業務為例,辦理業務是個模板方法,普通人要經歷排隊、取號、等待、辦理四個基本流程,而Vip則不需要排隊、取號、等待,那麼在設計的時候我們的抽象模板類需要考慮到,於是乎你得需要在模板方法各基本方法呼叫之前增加條件判斷,那麼用於設定這個條件的方法就是,鉤子方法(Hook Method),鉤子方法也可以是抽象的還可以由子類的一個方法返回值決定公共部分的執行結果。

二、模板方法的優點和缺點及常見可用場景

1、模板方法模式的優點

  • 良好的擴充套件性,封裝不變部分,擴充套件可變部分,把認為是不變部分的演算法封裝到父類實現,而可變部分的則可以通過繼承來繼續擴充套件。例如增加一個新的功能很簡單,只要再增加一個子類,實現父類的基本方法就可以了。

  • 提取公共部分程式碼,便於維護,減小維護升級成本,基本操作由父類定義,子類實現

  • 基本方法是由子類實現的,因此子類可以通過擴充套件的方式增加相應的功能,符合開閉原 則。

2、模板方法模式的缺點

通常抽象類是負責宣告某一類的事物的共同屬性和抽象方法,實現類則是完成定義具體的特性和方法。但是模板方法模式卻顛倒了,抽象類定義了部分抽象方法,由子類實現,子類執行的結果影響了父類的結果,也就是子類對父類產生了影響,可能會讓新手產生不適感,以下不理解程式碼。

3、適合使用模板方法模式的場景

  • 多個子類有公有的方法,並且邏輯基本相同時。

  • 重要、複雜的演算法,可以把核心演算法設計為模板方法,周邊的相關細節功能則由各個 子類實現。

  • 重構時,模板方法模式是一個經常使用的模式,把相同的程式碼抽取到父類中,然後通過鉤子方法約束其行為。

三、模板方法的實現

如下圖所示模板方法模式很簡單,通俗來說模板方法本質上封裝了一個固定的工作流程,相似的一類事務都按照固定的流程來執行,整個結構就全部在一個抽象模板類裡


2647955-4b569070c59e719e
這裡寫圖片描述

前面所說模板方法模式是基於繼承的程式碼複用基本技術,在模板方法模式中,可以將相同的程式碼放在父類中,而將不同的方法實現放在不同的子類中。所以實現起來步驟很簡單:

1、定義抽象模板類

將部分邏輯以具體方法以及具體建構函式的形式實現,然後宣告一些抽象方法來讓子類實現剩餘的邏輯,並且定義鉤子方法控制基本方法的執行。

public abstract class AbstractClass {
    //基本方法1
    protected abstract void doOneStep();
    //基本方法2
    protected abstract void doSecStep();
    //基本方法3
    protected abstract void doThirdStep();
    
    //模板方法,為了避免被子類覆寫改變模板方法的演算法骨架一般使用final修飾,可以有N個模板方法
    public final void work(){
        /*
        * 呼叫基本方法,完成相關的邏輯
        */
        if(oneStepNeedRun){//鉤子方法控制基本方法是否執行
            this.doOneStep();
        }
        this.doSecStep();
        
        this.doThirdStep();
    }
    
    //鉤子方法它在抽象類中不做事或者是預設的事情,子類可以選擇覆蓋它,可以有N個
    protected boolean oneStepNeedRun(){
        return true;
    }
}

2、繼承抽象模板類實現具體模板類

就是普通的繼承,根據各自的業務需要可以選擇是否覆寫鉤子方法的實現邏輯。

public class ConcreteClass extends AbstractClass {
    //實現基本方法
    protected void doOneStep() {
    //業務邏輯處理
    }
    protected void doSecStep() {
    //業務邏輯處理
    }
    protected void doThirdStep() {
    //業務邏輯處理
    }
    
}

測試

public class TemplateMethod {
    public static void main(String[] args) {
        AbstractClass obj = new ConcreteClass();//多型構建
        //呼叫模板方法
        obj.work();
    }
}

小結

  • 模板方法模式是一種類的行為型模式,在它的結構圖中只有類之間的繼承關係,沒有物件關聯關係。

  • 模板方法模式是基於繼承和多型的程式碼複用基本技術

  • 在模板方法模式中,將固定的相同的功能的程式碼段放在父類並在父類中實現,而將需要根據業務而各自實現的方法統一抽象到父類而把實現延遲到不同的子類中。

  • 在模板方法模式中,結構很簡單一個抽象類和若干個具體實現子類,抽象類即抽象模板只是定義了基本的操作方法(抽象模板中的基本方法儘量設計為protected型別,符合迪米特法則,不需要暴露
    的屬性或方法儘量不要設定為protected型別。實現類若非必要,儘量不要擴大父類中的訪問
    許可權。)而把實現延遲到子類中實現、以及實現了用於規範基本方法呼叫流程的模板方法(一般將模板方法宣告為final),最後還可以根據具體的業務區定義鉤子方法用於控制基本方法的執行。

  • 最後策略模式和模板方法模式都是用於封裝演算法,前者是利用組合和委託模型,而後者則是繼承。

相關文章