設計模式之模板方法模式(三)
- 2019 年 12 月 26 日
- 筆記
模板方法模式是一個很常見的模式,但是也需要我們擁有一雙銳利的眼睛,因為模板方法有許多實現,而他們看起來並不一定和書上所講的設計一致。
這個模式很常見是因為對創建框架來說,這個模式簡直棒極了。由框架控制如何做事情,而由你(使用這個框架的人)指定框架算法中每個步驟的細節。
用模板方法排序
我們經常需要數組做什麼事情?對了!排序。
Java數組類的設計者提供給我們一個方便的模板方法用來排序。讓我們看看這個方法如何運行:
這裡有兩個方法,共同提供排序的功能,這裡提供了Java的部分源碼
public static void sort(Object[] a) { Object aux[] = (Object[])a.clone(); mergeSort(aux, a, 0, a.length, 0); } private static void mergeSort(Object[] src, Object[] dest,int low,int high, int off) { // 這裡省略其他實現 int length = high - low; if (length < INSERTIONSORT_THRESHOLD) { 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); return; } // 這裡省略其他實現 }
排序鴨子
加入我們有一個鴨子的數組需要排序,你要怎麼做?數組的排序模板方法已經提供了算法,但是你必須讓這個模板方法知道如何比較鴨子。你要做的事情就是,實現一個compareTo()方法。
事情是這樣的:sort()的設計者希望這個方法能使用於所有的數組,所以他們把sort變成是靜態方法,這樣一來,任何數組都可以使用這個方法。但是沒關係,它使用起來和它被定義在超類是一樣的。現在,還有一個細節要告訴你:因為sort並不是真正定義在超類中,所以sort方法需要知道你已經實現了這個compareTo方法,否則就無法進行排序。
要達到這一點,設計者利用了Comparable接口。你須實現這個接口,提供這個接口所聲明的方法,也就是compareTo()。
public class Duck implements Comparable<Duck> { String name; int weight; public Duck(String name, int weight) { this.name = name; this.weight = weight; } public String toString() { return name + " weighs " + weight; } public int compareTo(Duck object) { Duck otherDuck = object; if (this.weight < otherDuck.weight) { return -1; } else if (this.weight == otherDuck.weight) { return 0; } else { // this.weight > otherDuck.weight return 1; } } }
讓我們來測試下這個程序
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) }; System.out.println("Before sorting:"); display(ducks); Arrays.sort(ducks); System.out.println("nAfter sorting:"); display(ducks); } public static void display(Duck[] ducks) { for (Duck d : ducks) { System.out.println(d); } } }
觀察鴨子排序的內部工作
讓我們追蹤Array類的sort模板方法的工作過程。我們會看到模板方法是如何控制算法的,以及在算法中的某些點上它是如何要求我們的鴨子提供某個步驟的實現的
- 首先我們需要鴨子數組
- 然後調用Array類的sort模板方法,並傳入鴨子數組
- 想要排序一個數組,你需要一次又一次地比較兩個項目,直到整個數組都排序完畢
- 如果鴨子的次序不對,就用Array的具體swap方法將兩者對調
- 排序方法會持續比較並對調鴨子,直到整個數組次序是正確的
是不是很驚訝,這個也是模板方法的一種實現呢。雖然不是教科書上的模板方法,但它的實現仍然符合模板方法模式的精神。在Java的API中,還可以看到其他的。比如java.io的InputStream類有一個read()方法,是由子類實現的,而這個方法又會被read(byte b[],int off,int len)模板方法使用。
還有模板方法和策略模式都是封裝組合,一個用組合,一個用繼承,你搞明白了嗎?如果還是太籠統的話,那麼,小編請你仔細翻書《Head First設計模式》看一下這章吧,然後我們再討論。
設計箱內的工具
總結時間到了
- OO基礎 抽象、封裝、繼承、多態
- OO原則 封裝變化 多用組合,少用繼承 針對接口編程,不針對實現編程 為交互對象之間的松耦合設計而努力 依賴抽象,不要依賴具體類 類應該對擴展開放,對修改關閉 只和朋友交談 別找我,我會找你(我們最新的原則提醒你,由超類主控一切,當它們需要的時候,自然會去調用子類,這就跟好萊塢一樣) 只和朋友交談
- OO模式 『策略模式』、『觀察者模式』、『裝飾者模式』、『抽象工廠模式』、『工廠方法模式』、『單例模式』、『命令模式』、『適配器模式』、『外觀模式』 『模板方法模式』在一個方法中定義一個算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以在不改變算法結構的情況下,重新定義算法中的某些步驟。
學習完模板方法模式,小編才知道,原來在平時頻繁使用的設計模式中,他也佔據着一個重要的地位,學習之前,小編是全然不知呀。這次終於get到這個模式,並且儲備了知識,還需要慢慢消化噢。
下次,我們一起走進迭代器和組合模式的世界。
愛生活,愛學習,愛感悟,愛挨踢