設(shè)計模式之模板方法

設(shè)計模式之模板方法

image

1.意圖

根據(jù)GOF中的定義:定義一個操作中的算法的骨架刹泄,而將一些步驟延遲到子類中實現(xiàn)脏答。模板方法使得子類可以不改變一個算法的結(jié)構(gòu)就可重定義算法的某些特定步驟躲撰。

很明顯,模板方法就是抽象出某個問題的解決算法,封裝算法框架嗅虏,開放一些特定步驟讓子類繼承抽象類后重新定義扎阶,從而實現(xiàn)改變這個解決算法事富。這在實際中是實用很廣的算法。

2.動機(jī)

這樣做有很大的好處乘陪,最重要的一點(diǎn)我認(rèn)為是根據(jù)某個問題的解決算法而定制化算法的特定步驟统台,做到使算法或操作框架穩(wěn)定,而實現(xiàn)步驟特定化啡邑,提高代碼的復(fù)用性贱勃。

模板方法通過一些抽象的操作定義一個算法,子類重定義這些操作谤逼,模板方法確定這些操作的順序贵扰,實現(xiàn)滿足各自的需求。

3.模式結(jié)構(gòu)與角色定義

image

如圖流部,抽象類定義某些特定步驟戚绕,然后templateMethod對這些操作確定順序(需要的話可以添加課外的邏輯代碼),具體類繼承抽象類枝冀,重定義這些特定的步驟舞丛。有時候耘子,在這個結(jié)構(gòu)中還有一個鉤子函數(shù),是用于控制模板方法的某些邏輯球切,一般是把鉤子函數(shù)放在抽象類中谷誓,然后具體類通過重寫鉤子函數(shù)來影響模板方法的邏輯,這樣做的好處是以防多個不同子類需要重新定義鉤子函數(shù)吨凑。這樣一個完整的模板方法就完成了捍歪。

在這個模板方法設(shè)計模式中,一共有以下的角色:

  • 1.AbstractClass:

  • 1.定義抽象的操作鸵钝,被子類繼承重寫以實現(xiàn)一個算法的步驟糙臼。

  • 2.定義好一個算法的骨架或特定步驟。

  • 2.ConcreteClass:

  • 1.繼承抽象類恩商,重寫各個步驟弓摘,以實現(xiàn)完善算法的步驟

4.應(yīng)用場景

1.一次性實現(xiàn)算法的不變部分,并將可變的行為留給子類實現(xiàn)痕届。

2.各子類將公共的部分提取出來抽象父類韧献,然后各自繼承重寫特定操作,提高代碼的復(fù)用性

3.控制拓展子類研叫。通過鉤子函數(shù)锤窑,子類也可以控制算法的某些步驟邏輯。

5.模式的實現(xiàn)步驟與例子

模板的實現(xiàn)可以簡單總結(jié)為:

1.提取出不變或者公共的架構(gòu)嚷炉,把變化的抽象化渊啰,抽象成抽象類或接口。

2.具體類繼承抽象類或接口申屹,重寫變化的步驟

3.客戶端實例化具體類绘证,直接調(diào)用模板方法解決問題。

例子:去3天馬爾代夫旅游哗讥,定好目的地嚷那,并且小情侶想每天嘗試不同的交通方式,因此每天的交通工具不一樣杆煞,但是目的地都是一樣的魏宽。因此可以說是總體的旅游路線是一致的,但是每天的交通方法不一樣决乎,所以可以定好一個去目的地的模板队询,然后只改變3天的交通方式,就可以了构诚。

//抽象類
#include <iostream>

/************************************************************************/
/* 定義旅游交通方式的接口 */
/************************************************************************/
class ITravel {
public:
    ITravel(){
        is_other = false; //默認(rèn)不坐其他交通方式
    }
    virtual ~ITravel(){}

protected:  
    virtual bool Day1() = 0;
    virtual void Day2() = 0;
    virtual void Day3() = 0;

public:
    //旅游路線模板
    void Travel() {
        std::cout<<"============旅行開始==========="<<std::endl;
        if (Day1())
        {
            Day2();
        }
        if (is_other)
        {
            std::cout<<"額外方式:坐火箭"<<std::endl;
        }
        Day3();
        std::cout<<"============旅行結(jié)束==========="<<std::endl;
        std::cout<<std::endl;
    }

    //鉤子函數(shù)
    virtual void SetAttrHood() = 0;
    void SetOther(bool other) {
        is_other = other;
    }

private:
    bool is_other;//是否乘坐其他
};

以上抽象類抽象出算法的框架蚌斩,并且定義好步驟。

//具體類A
class TravelA : public ITravel
{
public:
    TravelA(){}
    ~TravelA(){}

protected:
    bool Day1() override {
        std::cout<<"第一天:坐大巴"<<std::endl;
        return true;
    }

    void Day2() override {
        std::cout<<"第一天:坐飛機(jī)"<<std::endl;
    }

    void Day3() override {
        std::cout<<"第一天:坐輪船"<<std::endl;
    }
    
    void SetAttrHood() override {
        SetOther(true);
    }
};

具體類繼承抽象類范嘱,并且重寫特定的步驟送膳,定制化算法员魏。

//具體類B
class TravelB : public ITravel
{
public:
    TravelB(){}
    ~TravelB(){}

protected:
    bool Day1() override {
        std::cout<<"步驟一:坐飛機(jī)"<<std::endl;
        return true;
    }

    void Day2() override {
        std::cout<<"步驟二:坐輪船,"<<std::endl;
    }

    void Day3() override {
        std::cout<<"步驟三:坐大巴"<<std::endl;
    }

    void SetAttrHood() override {
        SetOther(false);
    }
};

具體類繼承抽象類肠缨,并且重寫特定的步驟逆趋,定制化算法盏阶。

//客戶端程序
#include "template_method.h"

int main()
{
    ITravel* travelA = new TravelA();
    travelA->SetAttrHood();
    travelA->Travel();

    ITravel* travelB = new TravelB();
    travelB->SetAttrHood();
    travelB->Travel();

    system("pause");

    delete travelA;
    delete travelB;
    return 0;
}

以下是打印結(jié)果:

============旅行開始===========
第一天:坐大巴
第一天:坐飛機(jī)
額外方式:坐火箭
第一天:坐輪船
============旅行結(jié)束===========

============旅行開始===========
步驟一:坐飛機(jī)
步驟二:坐輪船晒奕,
步驟三:坐大巴
============旅行結(jié)束===========

6.小結(jié)

模板方法是一個很常用的方法,能夠提高代碼的復(fù)用性名斟,關(guān)鍵點(diǎn)是找出解決一個問題的變與不變的分層點(diǎn)脑慧,封裝不變的,定義好骨架砰盐,留出變化的給子類重寫實現(xiàn)闷袒,就可以使同一個算法框架,被實現(xiàn)成解決相似的問題岩梳。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末囊骤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子冀值,更是在濱河造成了極大的恐慌也物,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件列疗,死亡現(xiàn)場離奇詭異滑蚯,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)抵栈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進(jìn)店門告材,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人古劲,你說我怎么就攤上這事斥赋。” “怎么了产艾?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵灿渴,是天一觀的道長。 經(jīng)常有香客問我胰舆,道長骚露,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任缚窿,我火速辦了婚禮棘幸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘倦零。我一直安慰自己误续,他們只是感情好吨悍,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蹋嵌,像睡著了一般育瓜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上栽烂,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天躏仇,我揣著相機(jī)與錄音,去河邊找鬼腺办。 笑死焰手,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的怀喉。 我是一名探鬼主播书妻,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼躬拢!你這毒婦竟也來了躲履?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤聊闯,失蹤者是張志新(化名)和其女友劉穎工猜,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體馅袁,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡域慷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了汗销。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片犹褒。...
    茶點(diǎn)故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖弛针,靈堂內(nèi)的尸體忽然破棺而出叠骑,到底是詐尸還是另有隱情,我是刑警寧澤削茁,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布宙枷,位于F島的核電站,受9級特大地震影響茧跋,放射性物質(zhì)發(fā)生泄漏慰丛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一瘾杭、第九天 我趴在偏房一處隱蔽的房頂上張望诅病。 院中可真熱鬧,春花似錦、人聲如沸贤笆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芥永。三九已至篡殷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間埋涧,已是汗流浹背板辽。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留飞袋,地道東北人戳气。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓链患,卻偏偏與公主長得像巧鸭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子麻捻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評論 2 355

推薦閱讀更多精彩內(nèi)容