我的設計模式之旅。本節學習模板方法模式。從多個類包含許多相似代碼的問題中思考如何在保持演算法結構完整的情況下去除重覆代碼。介紹了模板方法模式的概念和實現方法。 ...
編程旅途是漫長遙遠的,在不同時刻有不同的感悟,本文會一直更新下去。
思考總結
思考問題
- 多個類中包含許多相似代碼,只是小部分代碼不同。思考如何在保持演算法結構完整的情況下去除重覆代碼。
什麼是模板方法模式
模板方法是一種行為設計模式, 它在超類中定義了一個演算法的框架,允許子類在不修改結構的情況下重寫演算法的特定步驟。
模板方法模式:定義一個操作中的演算法的骨架,將一些步驟延遲到子類中。模板方法使得子類可以不改變一個演算法的結構即可重新定義該演算法的某些特定步驟。
含義:
- 模板方法模式建議將演算法分解為一系列步驟,然後將這些步驟改寫為方法, 最後在“模板方法”中依次調用這些方法。 步驟可以是抽象 的,也可以有一些預設的實現。為了能夠使用演算法,客戶端需要自行提供子類並實現所有的抽象步驟。 如有必要還需重寫一些步驟(但這一步中不包括模板方法自身)。
- 抽象步驟必須由各個子類來實現。可選步驟已有一些預設實現,但仍可在需要時進行重寫。
還有另一種名為鉤子的步驟。鉤子是內容為空的可選步驟。 即使不重寫鉤子,模板方法也能工作。鉤子通常放置在演算法重要步驟的前後,為子類提供額外的演算法擴展點。
何時使用:
- 當你只希望客戶端擴展某個特定演算法步驟,而不是整個演算法或其結構時,可使用模板方法模式。
- 模板方法將整個演算法轉換為一系列獨立的步驟,以便子類能 對其進行擴展,同時還可讓超類中所定義的結構保持完整。
- 當多個類的演算法除一些細微不同之外幾乎完全一樣時,你可使用該模式。但只要演算法發生變化,你就可能需要修改所有的類。
- 將相似的實現步驟提取到超類中以去除重覆代碼。子類間各不同的代碼可繼續保留在子類中。
實現方式:
- 分析目標演算法,確定能否將其分解為多個步驟。從所有子類的角度出發,考慮哪些步驟能夠通用,哪些步驟各不相同。
- 創建抽象基類並聲明一個模板方法和代表演算法步驟的一系列抽象方法。 在模板方法中根據演算法結構依次調用相應步驟。
- JAVA中可用 final 最終修飾模板方法以防止子類對其進行重寫。
- 預設實現會給部分步驟帶來好處,子類無需實現那些方法。
- 可考慮在演算法的關鍵步驟之間添加鉤子。方便子類提供額外的演算法擴展點。
- 為每個演算法變體新建一個具體子類,它必須實現所有的抽象步驟,也可以重寫部分可選步驟。
應用實例:
- 在造房子的時候,地基、走線、水管都一樣,只有在建築的後期才有加壁櫥加柵欄等差異。
- 西游記裡面菩薩定好的 81 難,這就是一個頂層的邏輯骨架。
優點:
- 封裝不變部分,擴展可變部分。重覆代碼提取到一個超類中。
- 提取公共代碼,便於維護。 你可僅允許客戶端重寫一個大型演算法中的特定部分,使得演算法其他部分修改對其所造成的影響減小。
- 行為由父類控制,子類實現。
缺點:
- 每一個不同的實現都需要一個子類來實現,導致類的個數增加,使得系統更加龐大。
- 部分客戶端可能會受到演算法框架的限制。
- 通過子類抑制預設步驟實現可能會導致違反里氏替換原則。
- 模板方法中的步驟越多,其維護工作就可能會越困難。
與其他模式的關係
- 工廠方法是模板方法的一種特殊形式。同時,工廠方法可以作為一個大型模板方法中的一個步驟。
- 模板方法基於繼承機制:它允許你通過擴展子類中的部分內容來改變部分演算法。策略基於組合機制:你可以通過對相應行為提供不同的策略來改變對象的部分行為。模板方法在類層次上運作,因此它是靜態的。策略在對象層次上運作,因此允許在運行時切換行為。
參考資料
- 《Go語言核心編程》李文塔
- 《Go語言高級編程》柴樹彬、曹春輝
- 《大話設計模式》程傑
- 《深入設計模式》亞歷山大·什韋茨
- 菜鳥教程