趣谈设计模式 | 模板方法模式(Template Method):封装不变部分,扩展可变部分
文章目錄
- 案例:房屋建造
- 模板方法模式
- 模板方法模式與策略模式
- 總結(jié)
- 完整代碼與文檔
這個(gè)設(shè)計(jì)模式過于簡(jiǎn)單,所以不是很好舉例…
案例:房屋建造
假設(shè)我們是建筑公司中的規(guī)劃者,負(fù)責(zé)設(shè)定建筑方案,在初期我們主要承接兩種裝修方案,分別是下圖的中式裝修與西式裝修
代碼表示如下
隨著公司不斷發(fā)展,承接的項(xiàng)目也越來越多,我們開始往新的設(shè)計(jì)方案發(fā)展,如日式、歐式、復(fù)古式、奢華式等風(fēng)格,但是在項(xiàng)目的拓展中,我們遇到了問題。
上面的代碼中存在著嚴(yán)重的設(shè)計(jì)問題,我們將同樣的代碼重復(fù)寫了多次,不僅僅降低了效率,還可能會(huì)因?yàn)槭韬鰧?dǎo)致錯(cuò)誤,缺少代碼復(fù)用。
雖然建筑方案不同,但是其中的地基、建筑房屋等步驟是永恒不變的,變化的只有設(shè)計(jì)與裝修,我們可以將其抽象出來,設(shè)定為一個(gè)裝修的抽象模板類,而那些具體風(fēng)格的實(shí)現(xiàn),則放到派生類中進(jìn)行
設(shè)計(jì)方案如下
由于房屋建造的順序是固定的,并且地基和房屋建造都是完全相同的步驟,只有后期的設(shè)計(jì)與裝修才是不同的,因此我們將那部分相同的內(nèi)容定義為final,然后將不同的部分抽象為接口,讓具體派生類實(shí)現(xiàn)。
class BuildTemplate { public:virtual ~BuildTemplate() = default;virtual void TemplateMethod() final {Foundation();Build();Design();Renovation();}protected:virtual void Design() = 0;virtual void Renovation() = 0;virtual void Foundation() final{std::cout << "打地基" << std::endl;}virtual void Build() final{std::cout << "建筑房屋" << std::endl;} };接著在派生類中完成具體設(shè)計(jì)與裝修的實(shí)現(xiàn)
class WesternStyle : public BuildTemplate { protected:void Design() override{std::cout << "設(shè)計(jì)出西式風(fēng)格的裝修計(jì)劃" << std::endl;}void Renovation() override{std::cout << "將房屋裝修為西式風(fēng)格" << std::endl; } };class ChineseStyle : public BuildTemplate { protected:void Design() override{std::cout << "設(shè)計(jì)出中式風(fēng)格的裝修計(jì)劃" << std::endl;}void Renovation() override{std::cout << "將房屋裝修為中式風(fēng)格" << std::endl; } };下面進(jìn)行一下測(cè)試
int main() {BuildTemplate* chinese = new ChineseStyle;BuildTemplate* western = new WesternStyle;chinese->TemplateMethod();cout << endl;western->TemplateMethod();delete chinese, western;return 0; }
上面的這種設(shè)計(jì)方法,就是模板方法模式
模板方法模式
模板方法模式定義一個(gè)操作中的算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。
模板方法模式由以下兩部分組成
- AbstractClass(抽象基類):實(shí)現(xiàn)了一個(gè)模板方法,定義算法的骨架,將一些會(huì)變化的操作封裝為接口讓子類實(shí)現(xiàn)
- ConcreteClass(派生類):子類實(shí)現(xiàn)接口來完成那些與自己相關(guān)的操作
從上面的例子中可以看出,當(dāng)不變的行為和可變的行為混合在一起時(shí),就會(huì)導(dǎo)致不變的行為重復(fù)的出現(xiàn),存在大量的代碼冗余現(xiàn)象。
因此我們可以通過模板方法模式將這兩部分分離,將不變的部分移動(dòng)到父類中,而變化的部分就由子類來實(shí)現(xiàn),這樣就能夠使得我們的設(shè)計(jì)具有良好的代碼復(fù)用能力。
模板方法模式與策略模式
在之前的博客博客中我還提到過另一個(gè)封裝算法的模式,也就是策略模式
趣談設(shè)計(jì)模式 | 策略模式(Strategy):你還在使用冗長(zhǎng)的if-else嗎?
雖然它們兩個(gè)同樣是封裝算法,但是它們的意圖完全不同。
對(duì)于模板方法模式來說,父類定義出一個(gè)算法的骨架,將算法中不變的部分放入骨架中,而變化的部分則通過繼承交由子類實(shí)現(xiàn),因此算法的控制權(quán)主要掌握在父類手中。主要目的就是用于代碼復(fù)用
對(duì)于策略模式來說,由于其使用對(duì)象組合的方式,將具體算法委托給策略類,因此其放棄了對(duì)算法的控制,但也因此客戶能夠隨意的根據(jù)情況來切換不同的算法,更加具有彈性。它的主要目的就是用于根據(jù)問題的不同情況來切換不同的算法解決問題
總結(jié)
要點(diǎn)
- 將算法中公共的、不變的部分封裝為父類的模板,而變化的部分則交給子類實(shí)現(xiàn)
- 為了防止模板被修改,需要將其聲明為final
- 策略模式和模板方法模式都封裝算法,一個(gè)使用組合,一個(gè)使用繼承,一個(gè)封裝完整的算法,一個(gè)封裝算法的細(xì)節(jié)
應(yīng)用場(chǎng)景
- 有多個(gè)子類共有的方法,且邏輯相同
- 重要的、復(fù)雜的方法,可以考慮作為模板方法
完整代碼與文檔
如果有需要完整代碼或者markdown文檔的同學(xué)可以點(diǎn)擊下面的github鏈接
github
總結(jié)
以上是生活随笔為你收集整理的趣谈设计模式 | 模板方法模式(Template Method):封装不变部分,扩展可变部分的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 趣谈设计模式 | 适配器模式(Adapt
- 下一篇: 趣谈设计模式 | 职责链模式(Chain