C/Cpp / 设计模式 / 模板模式
一、定義
定義一個(gè)操作中的框架,而將一些步驟延遲到子類中。使得子類可以不改變邏輯的情況下即可重定義該算法的某些特定步驟。
二、栗子
1、模板方法模式(通用版)
(1)UML圖
(2)UML說明
AbstractClass 叫抽象模板,其方法分為兩類:
基本方法:即基本操作,是由子類實(shí)現(xiàn)的方法,并且在模板方法被調(diào)用。
模板方法:可以有一個(gè)或幾個(gè),一般是一個(gè)具體方法,即一個(gè)框架,實(shí)現(xiàn)對(duì)基本方法的調(diào)度,完成固定的邏輯
注:為了防止被惡意操作,C++中可以使用兩種方式
- ?模板方法為虛函數(shù),但是需要加上 final 關(guān)鍵字,使之在子類中不被覆寫。
- ?模板方法為非虛函數(shù)。
類圖中的 ConcreteClass1 和 ConcreteClass2 屬于具體模板,實(shí)現(xiàn)父類所定義的一個(gè)或多個(gè)抽象方法,也就是父類定義的基本方法在子類中得以實(shí)現(xiàn)。
(3)代碼
注:抽象模板中的基本方法盡量設(shè)計(jì)為 protected 類型,符合迪米特法則,不需要暴露的屬性或方法盡量不要設(shè)置為 protected 類型。實(shí)現(xiàn)類若非必要,盡量不要擴(kuò)大父類中的訪問權(quán)限。
#include <iostream>class AbstractClass { protected:virtual void doSomething() = 0; //基本方法virtual void doAngthing() = 0;public:virtual void templateMethod() final //模板方法{this->doSomething();this->doAngthing();} };class ConcreteClass1 : public AbstractClass { protected:virtual void doSomething() { std::cout << "ConcreteClass1 : doSomething" << std::endl; }virtual void doAngthing() { std::cout << "ConcreteClass1 : doAngthing" << std::endl; } };class ConcreteClass2 : public AbstractClass { protected:virtual void doSomething() { std::cout << "ConcreteClass2 : doSomething" << std::endl; }virtual void doAngthing() { std::cout << "ConcreteClass2 : doAngthing" << std::endl; } };int main() {AbstractClass *class1 = new ConcreteClass1();AbstractClass *class2 = new ConcreteClass2();class1->templateMethod();class2->templateMethod();delete class1;delete class2;return 0; }2、汽車模型
(1)UML圖
(2)UML說明
悍馬車有兩個(gè)型號(hào),H1 和 H2。按需求,只需要給出悍馬車模型。此處有一個(gè)抽象類,然后兩個(gè)不同型號(hào)的模型實(shí)現(xiàn)類,通過簡單繼承就可以實(shí)現(xiàn)業(yè)務(wù)需求。
(3)結(jié)構(gòu)說明
HummerModel 抽象類,在類中定義了發(fā)動(dòng)、停止、鳴笛、引擎、跑幾個(gè)方法。根據(jù)不同型號(hào)來進(jìn)行不同的實(shí)現(xiàn)。
(4)代碼
#include <iostream>class HummerModel { protected:virtual void start() = 0;virtual void stop() = 0;virtual void alarm() = 0;virtual void enginBoom() = 0;public:void run(){this->start();this->enginBoom();this->alarm();this->stop();} };class HummerH1Model : public HummerModel { protected:virtual void start() { std::cout << "HummerH1 : start" << std::endl; }virtual void stop(){std::cout << "HummerH1 : stop" << std::endl;}virtual void alarm(){std::cout << "HummerH1 : alarm" << std::endl;}virtual void enginBoom(){std::cout << "HummerH1 : enginBoom" << std::endl;} };class HummerH2Model : public HummerModel { protected:virtual void start(){std::cout << "HummerH2 : start" << std::endl;}virtual void stop(){std::cout << "HummerH2 : stop" << std::endl;}virtual void alarm(){std::cout << "HummerH2 : alarm" << std::endl;}virtual void enginBoom(){std::cout << "HummerH2 : enginBoom" << std::endl;} };int main() {HummerModel *h1 = new HummerH1Model();HummerModel *h2 = new HummerH2Model();h1->run();h2->run();return 0; }三、模板方法模式的應(yīng)用
1、優(yōu)點(diǎn)
- ?封裝不變部分,擴(kuò)展可變部分。例如,汽車模型中,增加一個(gè)H3型號(hào)的模型,增加一個(gè)子類,實(shí)現(xiàn)父類的基本方法就可以。
- ?提取公共部分代碼,便于維護(hù)。
- ?行為由父類控制,子類實(shí)現(xiàn)。
2、使用場(chǎng)景
- ?多個(gè)子類有共有的方法,并且邏輯基本相同時(shí)。
- ?重要、復(fù)雜的算法,可以把核心算法設(shè)計(jì)為模板方法,周邊相關(guān)細(xì)節(jié)功能由各個(gè)子類實(shí)現(xiàn)。
- ?重構(gòu)時(shí),把相同代碼抽取到父類中,通過鉤子函數(shù)(見“模板方法模式的擴(kuò)展”)約束其行為。
四、模板方法模式的擴(kuò)展
1、汽車模型
增加需求 H1的喇叭是否響可控,H2的喇叭不響。
(1)UML圖
(2)UML說明
在抽象類 HummerModel 中增加了一個(gè)實(shí)現(xiàn)方法 isAlarm,確定各個(gè)型號(hào)的車是否需要聲音,由各個(gè)實(shí)現(xiàn)類覆寫該方法,同時(shí)其他基本方法由于不需要對(duì)外提供訪問,因此也設(shè)計(jì)為 protected 類型。
(3)代碼
#include <iostream>class HummerModel { protected:virtual void start() = 0;virtual void stop() = 0;virtual void alarm() = 0;virtual void enginBoom() = 0;virtual bool isAlarm() { return true; }public:void run(){this->start();this->enginBoom();if (this->isAlarm()){this->alarm();}this->stop();} };class HummerH1Model : public HummerModel { public:void setAlarm(bool OK) { this->m_alarmFlag = OK; }protected:virtual void start() { std::cout << "HummerH1 : start" << std::endl; }virtual void stop() { std::cout << "HummerH1 : stop" << std::endl; }virtual void alarm() { std::cout << "HummerH1 : alarm" << std::endl; }virtual void enginBoom() { std::cout << "HummerH1 : enginBoom" << std::endl; }virtual bool isAlarm() { return this->m_alarmFlag; }private:bool m_alarmFlag; };class HummerH2Model : public HummerModel { protected:virtual void start() { std::cout << "HummerH2 : start" << std::endl; }virtual void stop() { std::cout << "HummerH2 : stop" << std::endl; }virtual void alarm() { std::cout << "HummerH2 : alarm" << std::endl; }virtual void enginBoom() { std::cout << "HummerH2 : enginBoom" << std::endl; }virtual bool isAlarm() { return false; } };int main() {HummerH1Model h1;HummerH2Model h2;h1.setAlarm(true);h1.run();h2.run();return 0; }五、最佳實(shí)踐
1、合適的方法
父類建立框架,子類重寫了父類部分方法后,再調(diào)用從父類繼承的方法,產(chǎn)生不同的結(jié)果,即模板方式。
2、開源框架中的使用
開源框架提供了一個(gè)抽象類,然后有一堆子類,如果需要擴(kuò)展功能,可以繼承這個(gè)抽象類,然后覆寫 protected 方法,然后調(diào)用一個(gè)類似 execute方法,即可擴(kuò)展。
?
(完)
總結(jié)
以上是生活随笔為你收集整理的C/Cpp / 设计模式 / 模板模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构与算法 / UUID 和 GUI
- 下一篇: Cpp 11 / override 和