TemplateMethodPattern模板方法模式

模板方法模式

1.定義

定義一個操做中的算法的框架,而將一些步驟的實現延遲到子類中,使得子類能夠不改變一個算法的結構便可重定義該算法的某些特定步驟。java

使用模板方法模式製造兩款汽車。定義汽車必須有的特質:可以發動,鳴笛和中止,不一樣型號的汽車實現不一樣。汽車生產完成後須要對汽車的質量進行檢驗,測試汽車的全部功能。算法

抽象汽車模型(抽象汽車類)框架

public abstract class AbstractCar {
    // 汽車能夠發動,發動方式不一樣,須要在實現類裏實現
    public abstract void start();
    // 汽車能夠鳴笛,但聲音不一樣,須要在實現類裏實現
    public abstract void alarm();
    // 汽車能夠熄火,中止方式也不一樣,須要在實現類裏實現
    public abstract void stop();

    // 測試汽車的質量,操做步驟同樣,先測試啓動,再測試喇叭,最後測試熄火
    public void run() {
        // 發動汽車
        this.start();
        // 按喇叭
        this.alarm();
        // 中止汽車
        this.stop();
    }
}

兩種不一樣型號的汽車(汽車實現類)測試

public class CarOne extends AbstractCar {
    // 發動C1型號的汽車
    public abstract void start() {
        System.out.println("手搖啓動C1型號的汽車");
    }
    // C1型號的汽車鳴笛
    public abstract void alarm() {
        System.out.println("C1型號的汽車鳴笛滴滴");
    }
    // 中止C1型號的汽車
    public abstract void stop() {
        System.out.println("鑰匙關閉C1型號的汽車");
    }
}

public class CarTwo extends AbstractCar {
    // 發動C2型號的汽車
    public abstract void start() {
        System.out.println("電子啓動C2型號的汽車");
    }
    // C2型號的汽車鳴笛
    public abstract void alarm() {
        System.out.println("C1型號的汽車鳴笛嗶嗶");
    }
    // 中止C2型號的汽車
    public abstract void stop() {
        System.out.println("電子關閉C1型號的汽車");
    }
}

測試汽車(場景類)this

public class Client {
    public static void main(String[] args) {
      	CarOne carOne = new CarOne();
      	carOne.run();

        CarTwo carTwo = new CarTwo();
      	carTwo.run();
    }
}

模板方法模式實現簡單,僅僅使用了java的繼承機制。以上述例子爲例,其中AbstractCar叫作抽象模板,它的方法分爲兩類:設計

  • 基本方法:由子類實現的方法,並在模板方法中被調用。
  • 模板方法:數量不限,通常是一個具體的方法,也就是定義中所說的算法,它實現對基本方法的調度,完成固定的邏輯。

CarOne和CarTwo叫作具體模板,實現抽象模板所定義的基本方法。code

注意:抽象模板中的基本方法儘可能設計爲protected類型,不須要i暴露的屬性或方法儘可能不要設置爲protected類型,實現類非必要的狀況,儘可能不擴大父類中的訪問權限。繼承

2.應用

2.1 優勢

  • 封裝不變部分,擴展可變部分。把不可變部分封裝到抽象模板中實現,可變部分經過繼承來繼續擴展。
  • 提取公共的代碼,便於後期的代碼維護。
  • 行爲由父類控制,子類只負責實現。

2.2 缺點

  • 抽象類定義了部分抽象方法,由子類實現,可是子類的執行結果對父類產生了影響,反過來又影響了父類的執行結果,帶來了代碼的閱讀難度。

2.3 使用場景

  • 多個子類有公有的方法,且邏輯基本相同。
  • 重要,複雜的算法設計爲模板方法,細節功能由子類實現。
  • 重構時,相同的代碼抽取到父類中,經過鉤子方法約束其行爲。

3.擴展

在上述造車的基礎上實現,C1型車能夠控制是否鳴笛,C2型車不鳴笛。鉤子

擴展後的汽車抽象模型模板

public abstract class AbstractCar {
    // 汽車能夠發動,發動方式不一樣,須要在實現類裏實現
    protected abstract void start();
    // 汽車能夠鳴笛,但聲音不一樣,須要在實現類裏實現
    protected abstract void alarm();
    // 汽車能夠熄火,中止方式也不一樣,須要在實現類裏實現
    protected abstract void stop();

    // 測試汽車的質量,操做步驟同樣,先測試啓動,再測試喇叭,最後測試熄火
    public final void run() {
        // 發動汽車
        this.start();
      
        if (this.isAlarm()) {
            // 按喇叭
            this.alarm();
        }

        // 中止汽車
        this.stop();
    }

    // 鉤子方法,默認喇叭會響
    protected boolean isAlarm() {
        return true;
    }
}

擴展後的汽車實現類

public class CarOne extends AbstractCar {
    // C1汽車要能夠鳴笛
    private boolean alarmFlag = true;

    // 發動C1型號的汽車
    protected abstract void start() {
        System.out.println("手搖啓動C1型號的汽車");
    }
    // C1型號的汽車鳴笛
    protected abstract void alarm() {
        System.out.println("C1型號的汽車鳴笛滴滴");
    }
    // 中止C1型號的汽車
    protected abstract void stop() {
        System.out.println("鑰匙關閉C1型號的汽車");
    }

    // 是否鳴笛由駕駛員控制
    public void setAlarm(boolean isAlarm) {
        this.isAlarm = isAlarm;
    }
}

public class CarTwo extends AbstractCar {
    // 發動C2型號的汽車
    protected abstract void start() {
        System.out.println("電子啓動C2型號的汽車");
    }
    // C2型號的汽車鳴笛
    protected abstract void alarm() {
        System.out.println("C1型號的汽車鳴笛嗶嗶");
    }
    // 中止C2型號的汽車
    protected abstract void stop() {
        System.out.println("電子關閉C1型號的汽車");
    }

    // C2汽車不能鳴笛
    protected boolean isAlarm() {
        return false;
    }
}

C1汽車由駕駛員控制是否鳴笛,抽象類中的isAlarm方法的返回值影響了run方法的執行結果,即外界條件的改變會影響到模板方法的執行,該方法就叫作鉤子方法

相關文章
相關標籤/搜索