TEMPLATE METHOD(模板方法) ———— 類行為型模式
意圖
定義一個操作中的算法骨架,而將一些步驟延遲到子類中。TemplateMethod使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。
適用性
- 需要固定定義算法骨架,實現(xiàn)一個算法的不變的部分,并把可變的行為留給子類來實現(xiàn)的情況;
- 各個子類中具有公共行為,應(yīng)該抽取出來,集中在一個公共類中去實現(xiàn),從而避免代碼重復(fù);
- 需要控制子類擴展的情況。模板方法模式會在特定的點來調(diào)用“hook”操作,這樣只允許在這些點進行擴展;
結(jié)構(gòu)
- AbstractClass(抽象類)
定義抽象的原語操作(primitive operation),具體的子類將重定義它們以實現(xiàn)一個算法的各步驟。
實現(xiàn)一個模板方法,定義一個算法的骨架。該模板方法不僅調(diào)用原語操作,也調(diào)用定義在AbstractClass或其他對象中的操作。 - ConcreteClass(具體類)
實現(xiàn)原語操作以完成算法中與特定子類相關(guān)的步驟。
認識模板方法模式
變與不變
程序設(shè)計的一個很重要的思考點就是“變與不變”,也就是分析程序中哪些功能是可變的,哪些功能是不變的,然后把不變的部分抽象出來,進行公共的實現(xiàn),把變化的部分分離出去,用接口來封裝隔離,或者是用抽象類來約束子類行為。
模板方法模式很好的體現(xiàn)了這一點。模板類實現(xiàn)的就是不變的方法和算法的骨架,而需要變化的地方,都通過抽象方法,把具體實現(xiàn)延遲到子類去了,而且還通過父類的定義來約束了子類的行為,從而使系統(tǒng)能有更好的復(fù)用性和擴展性。
好萊塢法則
什么是好萊塢法則呢?簡單點說,就是“不要找我們,我們會聯(lián)系你”。
模板方法模式很好的體現(xiàn)了這一點,做為父類的模板會在需要的時候,調(diào)用子類相應(yīng)的方法,也就是由父類來找子類,而不是讓子類來找父類。
這其實也是一種反向的控制結(jié)構(gòu),按照通常的思路,是子類找父類才對,也就是應(yīng)該是子類來調(diào)用父類的方法,因為父類根本就不知道子類,而子類是知道父類的,但是在模板方法模式里面,是父類來找子類,所以是一種反向的控制結(jié)構(gòu)。
對設(shè)計原則的體現(xiàn)
模板方法很好的體現(xiàn)了開閉原則和里氏替換原則。
首先從設(shè)計上,先分離變與不變,然后把不變的部分抽取出來,定義到父類里面,比如算法骨架,比如一些公共的、固定的實現(xiàn)等等。這些不變的部分被封閉起來,盡量不去修改它了,要擴展新的功能,那就使用子類來擴展,通過子類來實現(xiàn)可變化的步驟,對于這種新增功能的做法是開放的。
其次,能夠?qū)崿F(xiàn)統(tǒng)一的算法骨架,通過切換不同的具體實現(xiàn)來切換不同的功能,一個根本原因就是里氏替換原則,遵循這個原則,保證所有的子類實現(xiàn)的是同一個算法模板(為了防止子類改變模板方法中的算法,可以將模板方法聲明為final),并能在使用模板的地方,根據(jù)需要,切換不同的具體實現(xiàn)。
模板方法模式的實現(xiàn)
模板方法調(diào)用下列類型的操作
- 模板方法:就是定義算法骨架的方法 。
- 具體的操作:在模板中直接實現(xiàn)某些步驟的方法,通常這些步驟的實現(xiàn)算法是固定的,而且是不怎么變化的,因此就可以當(dāng)作公共功能實現(xiàn)在模板里面。如果不需提供給子類訪問這些方法的話,還可以是private的。這樣一來,子類的實現(xiàn)就相對簡單些。如果是子類需要訪問,可以把這些方法定義為protected final的,因為通常情況下,這些實現(xiàn)不能夠被子類覆蓋和改變了。
- 具體的AbstractClass操作:在模板中實現(xiàn)某些公共功能,可以提供給子類使用,一般不是具體的算法步驟的實現(xiàn),只是一些輔助的公共功能。
- 原語操作:就是在模板中定義的抽象操作,通常是模板方法需要調(diào)用的操作,是必需的操作,而且在父類中還沒有辦法確定下來如何實現(xiàn),需要子類來真正實現(xiàn)的方法。
- 鉤子操作:在模板中定義,并提供默認實現(xiàn)的操作。這些方法通常被視為可擴展的點,但不是必須的,子類可以有選擇的覆蓋這些方法,以提供新的實現(xiàn)來擴展功能。比如:模板方法中定義了5步操作,但是根據(jù)需要,某一種具體的實現(xiàn)只需要其中的1、2、3這幾個步驟,因此它就只需要覆蓋實現(xiàn)1、2、3這幾個步驟對應(yīng)的方法。那么4和5步驟對應(yīng)的方法怎么辦呢,由于有默認實現(xiàn),那就不用管了。也就是說鉤子操作是可以被擴展的點,但不是必須的。
-
Factory Method:在模板方法中,如果需要得到某些對象實例的話,可以考慮通過工廠方法模式來獲取,把具體的構(gòu)建對象的實現(xiàn)延遲到子類中去。
模板方法模式實現(xiàn)中指的注意的問題:
① 使用訪問控制:必須重定義的原語操作須定義為abstract函數(shù)。模板方法自身不需要被重定義,并且也不應(yīng)該被重定義,為了防止子類改變模板方法中的算法,可以將模板方法聲明為final。
② 盡量減少原語操作:定義模板方法的一個重要目的是盡量減少一個子類具體實現(xiàn)算法時必須重定義的那些原語操作的數(shù)目。需要重定義的操作越多,客戶程序就越冗長。
③ 命名約定:可以給應(yīng)被重定義的那些操作的名字加上一個前綴以識別它們。
優(yōu)缺點
優(yōu)點:
①實現(xiàn)代碼復(fù)用
模板方法模式是一種實現(xiàn)代碼復(fù)用的很好的手段。通過把子類的公共功能提煉和抽取,把公共部分放到模板里面去實現(xiàn)。
缺點:
①算法骨架不容易升級
模板方法模式最基本的功能就是通過模板的制定,把算法骨架完全固定下來。事實上模板和子類是非常耦合的,如果要對模板中的算法骨架進行變更,可能就會要求所有相關(guān)的子類進行相應(yīng)的變化。所以抽取算法骨架的時候要特別小心,盡量確保是不會變化的部分才放到模板中。
相關(guān)模式
模板方法模式 VS 工廠方法模式
這兩個模式可以配合使用。
模板方法模式可以通過工廠方法來獲取需要調(diào)用的對象。-
模板方法模式 VS 策略模式
模板方法會定義一個算法的大綱,然后由子類通過繼承來實現(xiàn)其中某些步驟的內(nèi)容;策略模式則是通過對象組合的方式,讓客戶可以選擇算法實現(xiàn)。即,使用委托來改變整個算法。但是,我們可以在模板方法中使用策略模式,就是把那些變化的算法步驟通過使用策略模式來實現(xiàn),但是具體選取哪個策略還是要由外部來確定,而整體的算法步驟,也就是算法骨架就由模板方法來定義了。
參考
《Head First 設(shè)計模式》
《設(shè)計模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》
《研磨設(shè)計模式》