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