《HeadFirst設計模式》讀書筆記-第8章-模板方法模式

定義

模板方法模式(template method pattern)在一個方法中定義一個算法的骨架,而將一些步驟延時到子類中。模板方法使得子類可以在不改變算法結構的情況下,重新定義算法中的某些步驟。

這裏寫圖片描述

下面給出了該類圖的代碼實現和說明:

public abstract class AbstractClass {
    /**
     * 這個是個模板方法
     * 聲明爲final是爲了防止子類覆蓋,以免子類改變這個算法的順序和結構
     */
    final void templateMethod() {
        primitiveOperation1();
        primitiveOperation2();
        concreteOperation();
        hook();
    }

    /**
     * 算法中的步驟,子類根據實際情況實現具體行爲
     */
    abstract void primitiveOperation1();
    abstract void primitiveOperation2();

    /**
     * 算法中的步驟
     * 聲明爲final是爲了防止子類覆蓋
     */
    final void concreteOperation() {
        // 這裏是具體實現
    }

    /**
     * 模板方法定義的鉤子
     * 鉤子的存在讓子類有能力在算法的一些重要時間點被通知,並可以去實現一些功能
     * 子類根據需要決定是否實現鉤子
     */
    void hook() {   
    }

}

模板方法中鉤子和抽象方法的區分:

  • 抽象方法是算法中不可缺少的,非常重要的步驟,子類必須實現。

  • 鉤子是可選的,子類自由選擇是否實現。

    鉤子的存在有兩個目的:

    • 對算法中不重要的,可選的細節讓子類進行實現,也可以不實現,使用默認的行爲

    • 通知算法執行時間節點的發生,類似回調函數

代碼實現

我們看看JDK是如何用模板方法來實現數組的排序的。

首先給出需要排序的對象類型,實現Comparable接口:

public class Duck implements Comparable {
    String name;
    int weight;

    public Duck(String name, int weight) {
        this.name = name;
        this.weight = weight;
    }

    public String toString() {
        return name + " weighs " + weight;
    }
        // Comparable接口中的方法,定義瞭如何實現Duck對象的比較    
    public int compareTo(Object object) {

        Duck otherDuck = (Duck) object;

        if (this.weight < otherDuck.weight) {
            return -1;
        } else if (this.weight == otherDuck.weight) {
            return 0;
        } else { // this.weight > otherDuck.weight
            return 1;
        }
    }
}

測試代碼:

import java.util.ArrayList;
import java.util.Arrays;

public class DuckSortTestDrive {

    public static void main(String[] args) {
        Duck[] ducks = { 
                        new Duck("Daffy", 8), 
                        new Duck("Dewey", 2),
                        new Duck("Howard", 7),
                        new Duck("Louie", 2),
                        new Duck("Donald", 10), 
                        new Duck("Huey", 2)
         };

        Arrays.sort(ducks);
    }
}

繼續看Arrays的sort()方法的實現,會發現最終由下面代碼片段實現排序:

/**
 * 排序dest[low:high]中的對象
 * compareTo()方法正是我們Duck對象實現的方法,
 * swap()是由Arrays類實現的方法,
 */
for (int i=low; i<high; i++)
    for (int j=i; j>low &&
      ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
        swap(dest, j, j-1);

這個模板方法和我們類圖中的不大一樣,差別在於標準的模板方法是定義了一個算法的框架,有子類實現某些具體的步驟。而這裏沒有用到繼承,這是因爲Array類的sort()方法的設計者收到一些約束:

他希望sort()方法適用於所有的數組,而每個數組都是不同的類,所以無法設計一個類繼承Java數組。

所以他把sort()方法定義成靜態方法,由被排序的數組元素對象實現Comparable接口,實現對象的比較動作,這個比較的方式可能每個類不一樣。swap()實現數組元素的交換,屬於通用的方法,所以由Array類實現。

所以上面的描述,sort()方法的設計符合模板方法模式的核心思想:定義了一個算法的框架,有具體類實現某些具體的步驟。

該模式體現了哪些OO原則

本章總結

  1. 模板方法模式爲我們提供了一種代碼複用的重要技巧

  2. 真實世界中有很多模板方法模式的變體,不一定都是標準的,比如Array.sort()方法

  3. 策略模式和模板方法模式都是封裝算法的,策略模式使用組合,模板方法模式使用的是繼承

  4. 策略模式封裝了完整的算法,模板方法只提供了算法的框架,需要具體類去實現某些步驟

  5. 工廠方法是模板方法的一種特殊版本,用於對象的創建

  6. 好萊塢原則告訴我們,將決策權放在高層模塊中,以便決定如何以及何時調用底層模塊

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章