設計模式之模板方法模式(二)

上一篇咱們已經學會了模板方法模式,此次咱們繼續來深刻學習下。畢竟學會只是第一步,還有更進一步的學習和深刻等着咱們呢。java

咱們先來看下,對模板方法模式的一個總結的類圖:算法

讓咱們細看抽象類是如何被定義的,包含了它內含的模板方法和原語操做。設計模式

abstract class AbstractClass {
// 這就是模板方法。它被聲明爲final,以避免子類改變這個算法的順序
    final void templateMethod() {
    // 模板方法定義了一連串的步驟,每一個步驟由一個方法表明
        primitiveOperation1();
        primitiveOperation2();
        concreteOperation();
        hook();
    }
    
    abstract void primitiveOperation1();
    
    abstract void primitiveOperation2();
    
    final void concreteOperation() {
        // 這裏是實現
    }
    
    // 這是一個具體的方法,但他什麼都不作。咱們叫它爲hook(鉤子),立刻就來揭曉它如何使用
    void hook();
}

對模板方法進行掛鉤

鉤子是一種被聲明在抽象類中的方法,但只有空的或者默認的實現。鉤子的存在,可讓子類有能力對算法的不一樣點進行掛鉤。要不要掛鉤,由子類決定。框架

鉤子有不少用途,咱們先看其中一個:學習

public abstract class CaffeineBeverageWithHook {
 
    final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        // 咱們加上一個小小的條件語句,該條件是否成立,是由一個具體方法決定
        if (customerWantsCondiments()) {
            addCondiments();
        }
    }
 
    abstract void brew();
 
    abstract void addCondiments();
 
    void boilWater() {
        System.out.println("Boiling water");
    }
 
    void pourInCup() {
        System.out.println("Pouring into cup");
    }
 
    // 這就是一個鉤子,子類能夠覆蓋這個方法,但不必定須要使用
    boolean customerWantsCondiments() {
        return true;
    }
}

爲了使用鉤子,咱們在子類中覆蓋它。在這裏,鉤子控制了咖啡因飲料是否執行某部分算法;好比,飲料中是否須要加進調料測試

public class CoffeeWithHook extends CaffeineBeverageWithHook {
 
    public void brew() {
        System.out.println("Dripping Coffee through filter");
    }
 
    public void addCondiments() {
        System.out.println("Adding Sugar and Milk");
    }
 
    public boolean customerWantsCondiments() {
        // 詢問用戶,是否要加調料
        String answer = getUserInput();

        if (answer.toLowerCase().startsWith("y")) {
            return true;
        } else {
            return false;
        }
    }
 
    private String getUserInput() {
        String answer = null;

        System.out.print("Would you like milk and sugar with your coffee (y/n)? ");

        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        try {
            answer = in.readLine();
        } catch (IOException ioe) {
            System.err.println("IO error trying to read your answer");
        }
        if (answer == null) {
            return "no";
        }
        return answer;
    }
}

上面就是一個鉤子,詢問顧客是否想要調料?若是須要,就執行內容,不然就不執行。測試代碼以下:設計

public class BeverageTestDrive {
    public static void main(String[] args) {
 
        Tea tea = new Tea();
        Coffee coffee = new Coffee();
 
        System.out.println("\nMaking tea...");
        tea.prepareRecipe();
 
        System.out.println("\nMaking coffee...");
        coffee.prepareRecipe();

 
        TeaWithHook teaHook = new TeaWithHook();
        CoffeeWithHook coffeeHook = new CoffeeWithHook();
 
        System.out.println("\nMaking tea...");
        teaHook.prepareRecipe();
 
        System.out.println("\nMaking coffee...");
        coffeeHook.prepareRecipe();
    }
}

執行結果以下:茶要加調料就給你加上了;咖啡不須要加調料,就沒給你加code

Making tea...
Boiling water
Steeping the tea
Pouring into cup
Would you like lemon with your tea (y/n)? y
Adding Lemon

Making coffee...
Boiling water
Dripping Coffee through filter
Pouring into cup
Would you like milk and sugar with your coffee (y/n)? n

那麼,咱們使用鉤子的真正目的是什麼呢?blog

鉤子有幾種用法。如咱們以前所說的,鉤子可讓子類實現算法中可選的部分,或者在鉤子對於子類的實現並不重要的時候,子類能夠對此鉤子置之不理。鉤子的另外一個用法,是讓子類可以 有機會對模板方法中某些即將發生的(或剛剛發生的)步驟作出反應。比方說,名爲justReOrderedList()的鉤子方法容許子類在內部列表從新組織後執行某些動做(例如在屏幕上從新顯示數據)。正如你剛剛看到的,鉤子也可讓子類有能力爲其抽象類作一些決定。ip

好萊塢原則

好萊塢原則:別調用(打電話給)咱們,咱們會調用(打電話給)你。

好萊塢原則能夠給咱們一種防止「依賴腐敗」的方法。當高層組件依賴低層組件,而低層組件又依賴高層組件,而高層組件又依賴邊側組件,而邊側組件又依賴低層組件時,依賴腐敗就發生了。在這種狀況下,沒有人能夠輕易地搞懂系統是如何設計的。

在好萊塢原則下,咱們容許低層組件將本身掛鉤到系統上,可是高層組件會決定何時和怎樣使用這些低層組件。換句話說,高層組件對待低層組件的方式是「別調用咱們,咱們會調用你」。

好萊塢原則和模板方法之間的鏈接其實還算明顯:當咱們設計模板方法時,咱們告訴子類「不要調用咱們,咱們會調用你」。怎樣才能辦到呢?讓咱們再看一次咖啡因飲料的設計:

咱們以前還知道一個原則叫依賴倒置原則,好萊塢原則也是有點這個味道的對吧。他們之間的關係是如何的呢?

依賴倒置原則教咱們儘可能避免使用具體類,而多實用抽象。而好萊塢原則是用在建立框架或組件上的一種技巧,好讓低層組件可以被掛鉤進計算中,並且又不會讓高層組件依賴低層組件。二者的目標都是在於解耦,可是以來倒置原則更加註重如何在設計中避免依賴。

好萊塢原則教咱們一個技巧,建立一個有彈性的設計,容許低層結構可以互相操做,而又防止其餘類太過於依賴它們。

這樣咱們就把開篇說的隱藏的原則給介紹完了,也更進一步的知道了模板方法模式鉤子的用法,讓咱們在實戰中能有一個更好的選擇。這個設計模式,你get到了嗎?

小編原本想在這完結的,可是看了下書,發現後面還有一個更貼近實際的,意想不到的模板方法,並且是咱們平時會使用到的,咱們下篇來聊聊。

愛生活,愛學習,愛感悟,愛挨踢

相關文章
相關標籤/搜索