設計模式之模板方法模式

csdnerM發表於2020-10-24

模板方法模式的定義

模板方法模式是類的行為模式。準備一個抽象類,將部分邏輯以具體方法以及具體建構函式的形式實現,然後宣告一些抽象方法來迫使子類實現剩餘的邏輯。不同的子類可以以不同的方式實現這些抽象方法,從而對剩餘的邏輯有不同的實現。這就是模板方法模式的用意。

moduledesign
模板方法模式

上面對模板方法模式的定義其實已經很清晰了。完成一件事情,有固定的數個步驟,但是每個步驟根據物件的不同,而實現細節不同;就可以在父類中定義一個完成該事情的總方法,按照完成事件需要的步驟去呼叫其每個步驟的實現方法。而每個步驟的具體實現,由子類完成。

模板方法模式的適用場景:還是使用通知服務的例子。有三種通知方式:應用服務內部通知、簡訊和郵件三種方式。傳送通知需要如下步驟:準備傳送通知的內容、傳送具體通知。這兩步是演算法的骨架,然而根據需要,可能使用三種方式中的任意一種,涉及具體細節。

模板方法模式的結構

這裡涉及到兩個角色:

  • 抽象模板(Abstract Template)角色。實現了模板方法,定義了演算法的骨架。

    • 定義了一個或多個抽象操作,以便讓子類實現。這些抽象操作叫做基本操作,它們是一個頂級邏輯的組成步驟。
    • 定義並實現了一個模板方法。這個模板方法一般是一個具體方法,它給出了一個頂級邏輯的骨架,而邏輯的組成步驟在相應的抽象操作中,推遲到子類實現。頂級邏輯也有可能呼叫一些具體方法。
  • 具體模板(Concrete Template)角色,實現抽象類中的抽象方法,完成完整的演算法。

    • 實現父類所定義的一個或多個抽象方法,它們是一個頂級邏輯的組成步驟。
    • 每一個抽象模板角色都可以有任意多個具體模板角色與之對應,而每一個具體模板角色都可以給出這些抽象方法(也就是頂級邏輯的組成步驟)的不同實現,從而使得頂級邏輯的實現各不相同。

模板方法模式的優點:

  • 具體細節步驟實現定義在子類中,子類定義詳細處理演算法是不會改變演算法整體結構。
  • 子類實現演算法的某些細節,有助於演算法的擴充套件。
  • 存在一種反向的控制結構,通過一個父類呼叫其子類的操作,通過子類對父類進行擴充套件增加新的行為,符合“開閉原則”。

模板方法模式的不足:

  • 每個不同的實現都需要定義一個子類,會導致類的個數增加,系統更加龐大。

模板方法模式的實現

抽象模板角色類實現:

public abstract class AbstractNotify {
	//模板方法
	public final void send() {
		String text = assembleContent();
		notice(text);
	}
	//基本方法,已經實現
	private String assembleContent() {
		return "content";
	}
	
    // 通知方法的宣告(由子類實現)
    public abstract void notice(String text);
}
複製程式碼

郵件通知具體模板實現:

public class MailNotify extends AbstractNotify {
    @Override
    public void notice(String text) {
        //相關的業務
    }
}
複製程式碼

簡訊通知具體模板實現:

public class SMSNotify extends AbstractNotify {
    @Override
    public void notice(String text) {
        //相關的業務
    }
}
複製程式碼

客戶端進行呼叫簡訊通知策略:

public class Client {
    public static void main(String[] args) {
        //選擇並建立需要使用的具體模板
        AbstractNotify notify = new SMSNotify();
        //SMS傳送
        notify.send();
    }
}
複製程式碼

總結

上面的實現中使用了JAVA的繼承機制,在抽象類中定義一個模板方法,該方法引用了若干個抽象方法(由子類實現)或具體方法(子類可以覆蓋重寫)。模板方法模式是一種類的行為型模式,在它的結構圖中只有類之間的繼承關係,沒有物件關聯關係。模板方法模式是基於繼承的程式碼複用基本技術,模板方法模式的結構和用法也是物件導向設計的核心之一。
在模板方法模式中,可以將相同的程式碼放在父類中,而將不同的方法實現放在不同的子類中。在模板方法模式中,我們需要準備一個抽象類,將部分邏輯以具體方法以及具體建構函式的形式實現,然後宣告一些抽象方法來讓子類實現剩餘的邏輯。不同的子類可以以不同的方式實現這些抽象方法,從而對剩餘的邏輯有不同的實現,這就是模板方法模式的用意。模板方法模式體現了物件導向的諸多重要思想,是一種使用頻率較高的模式。

上面的實現其實少了一個鉤子方法,它在抽象類中不做事,或者是預設的事情,子類可以選擇覆蓋它。 最後,為了防止子類改變模板方法中的演算法骨架,一般將模板方法宣告為final

vs策略方法模式

策略模式和模板方法都是用於封裝演算法,前者是利用組合和委託模型,而後者則是繼承。從具體實現來看,策略模式與模版方法模式的區別僅僅是多了一個單獨的封裝類Context,它與模版方法模式的區別在於:在模版方法模式中,呼叫演算法的主體在抽象的父類中,而在策略模式中,呼叫演算法的主體則是封裝到了封裝類Context中,抽象策略Strategy一般是一個介面,目的只是為了定義規範,裡面一般不包含邏輯。其實,這只是通用實現,而在實際程式設計中,因為各個具體策略實現類之間難免存在一些相同的邏輯,為了避免重複的程式碼,我們常常使用抽象類來擔任Strategy的角色,在裡面封裝公共的程式碼,因此,在很多應用的場景中,在策略模式中一般會看到模版方法模式的影子。

訂閱最新文章,歡迎關注我的公眾號

微信公眾號

參考

  1. 設計模式之 - 模板模式(Template Pattern)
  2. 《JAVA與模式》之模板方法模式

相關文章