1. 程式人生 > >設計模式——模板方法模式【Template Method Pattern】

設計模式——模板方法模式【Template Method Pattern】

 我先設計個類圖:

非常簡單的實現,你要悍馬模型,我就給你悍馬模型,先寫個抽象類,然後兩個不同型號的模型實現類,那我們把這個程式實現出來:

HummerModel抽象類的程式清單如下:

H1型號悍馬的定義如下:

然後看悍馬H2型號的實現:

 

然後程式寫到這裡,你就看到問題了,run方法的實現應該在抽象類上,不應該在實現類上,好,我們修改一下類圖和實現:

就把run方法放到了抽象類中,那程式碼也相應的改變一下,先看HummerModel.java:

下面是HummerH1Model.java程式清單:

下面是HummerH2Model.java的程式清單:

類圖修改完畢了,程式也該好了,提交給老大,老大一看,挺好,就開始生產了,並提交給客戶使用了,那客戶是如何使用的呢?類圖上增加一個Client類,就是客戶,我們這個是用main函式來代替他使用,類圖如下:

然後看增加的Client.java程式,非常的簡單:

非常非常的簡單,那如果我告訴這就是模板方法模式你會不會很不屑呢?就這模式,太簡單了,我一直在使用呀,是的,你經常在使用,但你不知道這是模板方法模式,那些所謂的高手就可以很牛X的說用模板方法模式就可以實現…,你還要很崇拜的看著,哇,牛人,模板方法模式是什麼呀?

然後我們繼續回顧我們這個模型,回頭一想,不對呀,需求分析的有點問題,客戶要關心模型的啟動,停止,鳴笛,引擎聲音嗎?他只要在run的過程中,聽到或看都成了呀,暴露那麼多的方法幹啥?好了,我們重新修改一下類圖:

把抽象類上的四個方法設定為protected訪問許可權,好了,既然客戶不關心這幾個方法,而且這四個方法都是由子類來實現的,那就設定成protected模式。咦~,那還有個缺陷,run方法既然子類都不修改,那是不是可以設定成final型別呢?是滴是滴,類圖如下:

好了,這才是模板方法模式,就是這個樣子,我們只要修改抽象類程式碼就可以了,HummerModel.java程式清單如下:

其他的子類都不用修改(如果要修改,就是把四個方法的訪問許可權由public修改protected),大家請看這個run方法,他定義了呼叫其他方法的順序,並且子類是不能修改的,這個叫做模板方法;startstopalarmengineBoom這四個方法是子類必須實現的,而且這四個方法的修改對應了不同的類,這個叫做基本方法,基本方法又分為三種:在抽象類中實現了的基本方法叫做具體方法;在抽象類中沒有實現,在子類中實現了叫做抽象方法,我們這四個基本方法都是抽象方法,由子類來實現的;還有一種叫做鉤子方法,這個等會講。到目前為止,這兩個模型都穩定的執行,突然有一天,老大又找到了我,客戶提出新要求了,那個喇叭想讓它響就響,你看你設計的模型,車子一啟動,喇叭就狂響,趕快修改一下,確實是設計缺陷,呵呵,不過是我故意的,那我們怎麼修改呢?看修改後的類圖:

 增加一個方法,isAlarm(),喇嘛要不要響,這就是鉤子方法(Hook Method),那我們只要修改一下抽象類就可以了:

鉤子方法模式是由抽象類來實現的,子類可以重寫的,H2型號的悍馬是不會叫的,喇叭是個擺設,看HummerH2Model.java程式碼:

H2型號的模型都沒有喇叭,就是按了喇叭也沒有聲音,那客戶端這邊的呼叫沒有任何修改,出來的結果就不同,我們先看Client.java程式:

H1又有所不同了,它的喇叭要不要響是由客戶來決定,其實在類圖上已經標明瞭setAlarm這個方法,我們看HummerH1Model.java的程式碼:

這段程式碼呢修改了兩個地方,一是重寫了父類的isAlarm()方法,一是增加了一個setAlarm方法,由呼叫者去決定是否要這個功能,也就是喇叭要不要滴滴答答的響,哈哈,那我們看看Client.java的修改:

看到沒,這個模型run起來就有聲音了,那當然把h1.setAlarm(false)執行起來喇叭就沒有聲音了,鉤子方法的作用就是這樣滴。