1、概念介紹模版方法模式的結構
定義一個操作中算法的框架,而將一些步驟延遲到子類中,使得子類可以不改變算法的結構即可重定義該算法中的某些特定步驟。
2、解決了什么問題
- 多個子類有公有的方法,并且邏輯基本相同時;
- 重要、復雜的算法,可以把核心算法設計為模板方法,周邊的相關細節功能則由各個子類實現;
- 重構時,模板方法模式是一個經常使用的模式,把相同的代碼抽取到父類中,然后通過鉤子函數約束其行為。
3、如何使用
模版方法模式由一個抽象類和一個(或一組)實現類通過繼承結構組成,抽象類中的方法分為三種:
抽象方法:父類中只聲明但不加以實現,而是定義好規范,然后由它的子類去實現。
模版方法:由抽象類聲明并加以實現。一般來說,模版方法調用抽象方法來完成主要的邏輯功能,并且,模版方法大多會定義為final類型,指明主要的邏輯功能在子類中不能被重寫。
鉤子方法:由抽象類聲明并加以實現。但是子類可以去擴展,子類可以通過擴展鉤子方法來影響模版方法的邏輯。
抽象類的任務是搭建邏輯的框架,通常由經驗豐富的人員編寫,因為抽象類的好壞直接決定了程序是否穩定性。
實現類用來實現細節。抽象類中的模版方法正是通過實現類擴展的方法來完成業務邏輯。只要實現類中的擴展方法通過了單元測試,在模版方法正確的前提下,整體功能一般不會出現大的錯誤。
模版方法的優點及適用場景
容易擴展。一般來說,抽象類中的模版方法是不易發生改變的部分,而抽象方法是容易發生變化的部分,因此通過增加實現類一般可以很容易實現功能的擴展,符合開閉原則。
便于維護。對于模版方法模式來說,正是由于他們的主要邏輯相同,才使用了模版方法,假如不使用模版方法,任由這些相同的代碼散亂的分布在不同的類中,維護起來是非常不方便的。
比較靈活。因為有鉤子方法,因此,子類的實現也可以影響父類中主邏輯的運行。但是,在靈活的同時,由于子類影響到了父類,違反了里氏替換原則,也會給程序帶來風險。這就對抽象類的設計有了更高的要求。
在多個子類擁有相同的方法,并且這些方法邏輯相同時,可以考慮使用模版方法模式。在程序的主框架相同,細節不同的場合下,也比較適合使用這種模式。
舉個例子:
我們使用沖泡咖啡和沖泡茶的例子
加工流程:
咖啡沖泡法:1.把水煮沸、2.用沸水沖泡咖啡、3.把咖啡倒進杯子、4.加糖和牛奶
茶沖泡法: ? 1.把水煮沸、2.用沸水沖泡茶葉、3.把 ?茶 倒進杯子、4.加蜂蜜
實踐步驟:
1>創建一個模板(抽象)類:Beverage(飲料)
package com.william.beverage;
public abstract class Beverage {
/**
* 沖泡咖啡或茶...流程
*/
public final void create(){
? ? ? ?boilWater();//把水煮沸
? ? ? ?brew();//用沸水沖泡...
? ? ? ?pourInCup();//把...倒進杯子
? ? ? ?addCoundiments();//加...
}
public abstract void addCoundiments();
public abstract void brew();
public void boilWater() {
? ? ? ?System.out.println("煮開水");
}
public void pourInCup() {
? ? ? ?System.out.println("倒進杯子");
}
}
package com.william.beverage;
public class Coffee extends Beverage{
@Override
public void addCoundiments() {
? ? ? ? ?System.out.println("添加糖和牛奶"); }
@Override
public void brew() {
? ? ? ? ? System.out.println("用水沖咖啡");
}
}