在一個樣板方法中,它的結構大概會長這樣:
class AbstractClass
{
void templateMethod()
{
primitiveOperation();
concreteOperation();
hook();
}
virtual void primitiveOperation(); // to be overrided by derived class
void concreteOperation()
{
// common operation
}
void hook() {} // do nothing
};
可以看到裡面有三種function,其中兩種我們前面介紹過,primitiveOperation()
指的是子類別各自實作方法的方法,而concreteOperation()
則是在樣板裡面定義實作,子類別共同使用的。而新的這個hook()
則是不做任何事情的預設具體方法,子類別可覆寫或忽略它。
它的用途,顧名思義,是供子類別可以掛入演算法中,它可以預設一種做法,讓子類別不一定要使用,例如以下的customerWantsCondiments()
是一種掛勾:
/*程式碼待補*/
它預設是直接回傳true,但子類別也可以選擇由其他判斷來取得結果。
要判斷掛勾與抽象方法的使用時機,可以看子類別是否必須要提供實作方法,來決定是不是要使用抽象方法來確保子類別必須覆寫這個方法;而掛鉤的目的就是讓子類別可以有選擇性的實作。
這次登場的原則有個非常炫的名字─好萊塢原則:
別打給 (call)我們 ,我們會打給 (call)你 。
看起來很摸不著頭腦,對應到物件導向的原則,它的用途是要避免 "依賴腐敗" 。有些高階組件會依賴低階組件,低階又想要依賴高階組件,又摻雜了用到的一些旁系組件...整個就糾纏不清!這樣會導致整個系統的設計無法被好好理清,影響維護。採取好萊塢原則的做法是將低階組件掛入系統,由高階組件決定使用方式,呼應到這個原則─低階組件不要呼叫(call)高階組件!高階組件來呼叫(call)低階組件。
而樣板方法模式跟好萊塢原則之間的關係呢?運用樣板方法模式其實就是在讓高階的抽象方法來進行呼叫,需要時才會呼叫子類別的實作,如下面的關係圖中,抽象飲料掌控樣板方法,用戶端只依賴抽象飲料,而不會依賴到Tea
或Coffee
這些低階組件!而Tea
、Coffee
也不會去主動呼叫抽象類別,只有飲料需要時才來跟它們要實作細節。
圖 1
而乍聽之下好萊塢原則與前面的依賴反轉原則([Day 13] 工廠模式 (3))很像,但依賴反轉原則主要是避免使用具體類別,盡量使用抽象;雖然兩者目的都是解耦合,但好萊塢原則是提供一種設計技巧,而依賴反轉原則則是更廣義的強調如何在設計中避免依賴關係。
好萊塢原則在平常使用也是深有感觸!常常在不同的類別中需要使用到其他類別的物件,引用來引用去,最後就糾纏不清,此時就可以秉持這個原則進行設計,將這些依賴關係用單向道的方式,低階的不要知道高階的內容,由高階的來統整使用。