模版方法模式
定義一個(gè)操作中算法的框架,而將一些步驟延遲到子類中。模板方法模式使得子類可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。

AbstractClass(抽象類):在抽象類中定義了一系列基本操作,這些基本操作可以是具體的,也可以是抽象的,每一個(gè)基本操作對(duì)應(yīng)算法的一個(gè)步驟,在其子類中可以重定義或?qū)崿F(xiàn)這些步驟。同時(shí),在抽象類中實(shí)現(xiàn)了一個(gè)模板方法(Template Method),用于定義一個(gè)算法的框架,模板方法不僅可以調(diào)用在抽象類中實(shí)現(xiàn)的基本方法,也可以調(diào)用在抽象類的子類中實(shí)現(xiàn)的基本方法,還可以調(diào)用其他對(duì)象中的方法。
ConcreteClass(具體子類):它是抽象類的子類,用于實(shí)現(xiàn)在父類中聲明的抽象基本操作以完成子類特定算法的步驟,也可以覆蓋在父類中已經(jīng)實(shí)現(xiàn)的具體基本操作。
#include<iostream>
using namespace std;
class DrinkTemplate{
public:
//煮水
virtual void BoildWater() = 0;
//沖泡
virtual void Brew() = 0;
//倒入杯中
virtual void PourInCup() = 0;
//加輔助料
virtual void AddSomething() = 0;
//模板方法
void Make(){
BoildWater();
Brew();
PourInCup();
AddSomething();
}
};
//沖泡咖啡
class Coffee : public DrinkTemplate{
public:
virtual void BoildWater(){
cout << "煮山泉水..." << endl;
}
//沖泡
virtual void Brew(){
cout << "沖泡咖啡..." << endl;
}
//倒入杯中
virtual void PourInCup(){
cout << "咖啡倒入杯中..." << endl;
}
//加輔助料
virtual void AddSomething(){
cout << "加糖,加牛奶,加點(diǎn)醋..." << endl;
}
};
//沖泡茶水
class Tea : public DrinkTemplate{
public:
virtual void BoildWater(){
cout << "煮自來(lái)水..." << endl;
}
//沖泡
virtual void Brew(){
cout << "沖泡鐵觀音..." << endl;
}
//倒入杯中
virtual void PourInCup(){
cout << "茶水倒入杯中..." << endl;
}
//加輔助料
virtual void AddSomething(){
cout << "加糖..加檸檬...加生姜..." << endl;
}
};
void test01(){
Tea* tea = new Tea;
tea->Make();
cout << "-----------" << endl;
Coffee* coffee = new Coffee;
coffee->Make();
}
int main(){
test01();
return 0;
}
模板方法的優(yōu)缺點(diǎn)及適用場(chǎng)景
優(yōu)點(diǎn):
(1)在父類中形式化地定義一個(gè)算法,而由它的子類來(lái)實(shí)現(xiàn)細(xì)節(jié)的處理,在子類實(shí)現(xiàn)詳細(xì)的處理算法時(shí)并不會(huì)改變算法中步驟的執(zhí)行次序。
(2)模板方法模式是一種代碼復(fù)用技術(shù),它在類庫(kù)設(shè)計(jì)中尤為重要,它提取了類庫(kù)中的公共行為,將公共行為放在父類中,而通過(guò)其子類來(lái)實(shí)現(xiàn)不同的行為,它鼓勵(lì)我們恰當(dāng)使用繼承來(lái)實(shí)現(xiàn)代碼復(fù)用。
(3)可實(shí)現(xiàn)一種反向控制結(jié)構(gòu),通過(guò)子類覆蓋父類的鉤子方法來(lái)決定某一特定步驟是否需要執(zhí)行。
(4)在模板方法模式中可以通過(guò)子類來(lái)覆蓋父類的基本方法,不同的子類可以提供基本方法的不同實(shí)現(xiàn),更換和增加新的子類很方便,符合單一職責(zé)原則和開(kāi)閉原則。
缺點(diǎn):
需要為每一個(gè)基本方法的不同實(shí)現(xiàn)提供一個(gè)子類,如果父類中可變的基本方法太多,將會(huì)導(dǎo)致類的個(gè)數(shù)增加,系統(tǒng)更加龐大,設(shè)計(jì)也更加抽象。
適用場(chǎng)景:
(1)具有統(tǒng)一的操作步驟或操作過(guò)程;
(2) 具有不同的操作細(xì)節(jié);
(3) 存在多個(gè)具有同樣操作步驟的應(yīng)用場(chǎng)景,但某些具體的操作細(xì)節(jié)卻各不相同;
在抽象類中統(tǒng)一操作步驟,并規(guī)定好接口;讓子類實(shí)現(xiàn)接口。這樣可以把各個(gè)具體的子類和操作步驟解耦合。
策略模式
策略模式定義了一系列的算法,并將每一個(gè)算法封裝起來(lái),而且使它們還可以相互替換。策略模式讓算法獨(dú)立于使用它的客戶而獨(dú)立變化。

Context(環(huán)境類):環(huán)境類是使用算法的角色,它在解決某個(gè)問(wèn)題(即實(shí)現(xiàn)某個(gè)方法)時(shí)可以采用多種策略。在環(huán)境類中維持一個(gè)對(duì)抽象策略類的引用實(shí)例,用于定義所采用的策略。
Strategy(抽象策略類):它為所支持的算法聲明了抽象方法,是所有策略類的父類,它可以是抽象類或具體類,也可以是接口。環(huán)境類通過(guò)抽象策略類中聲明的方法在運(yùn)行時(shí)調(diào)用具體策略類中實(shí)現(xiàn)的算法。
ConcreteStrategy(具體策略類):它實(shí)現(xiàn)了在抽象策略類中聲明的算法,在運(yùn)行時(shí),具體策略類將覆蓋在環(huán)境類中定義的抽象策略類對(duì)象,使用一種具體的算法實(shí)現(xiàn)某個(gè)業(yè)務(wù)處理。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
//抽象武器 武器策略
class WeaponStrategy{
public:
virtual void UseWeapon() = 0;
};
class Knife : public WeaponStrategy{
public:
virtual void UseWeapon(){
cout << "使用匕首!" << endl;
}
};
class AK47 :public WeaponStrategy{
public:
virtual void UseWeapon(){
cout << "使用AK47!" << endl;
}
};
class Character {
public:
void setWeapon(WeaponStrategy* weapon){
this->pWeapon = weapon;
}
void ThrowWeapon(){
this->pWeapon->UseWeapon();
}
public:
WeaponStrategy* pWeapon;
};
void test01(){
//創(chuàng)建角色
Character* character = new Character;
//武器策略
WeaponStrategy* knife = new Knife;
WeaponStrategy* ak47 = new AK47;
character->setWeapon(knife);
character->ThrowWeapon();
character->setWeapon(ak47);
character->ThrowWeapon();
delete ak47;
delete knife;
delete character;
}
int main(void){
test01();
return 0;
}
策略模式的優(yōu)缺點(diǎn)及適用場(chǎng)景
優(yōu)點(diǎn):
(1)策略模式提供了對(duì)“開(kāi)閉原則”的完美支持,用戶可以在不修改原有系統(tǒng)的基礎(chǔ)上選擇算法或行為,也可以靈活地增加新的算法或行為。
(2)使用策略模式可以避免多重條件選擇語(yǔ)句。多重條件選擇語(yǔ)句不易維護(hù),它把采取哪一種算法或行為的邏輯與算法或行為本身的實(shí)現(xiàn)邏輯混合在一起,將它們?nèi)坑簿幋a(Hard Coding)在一個(gè)龐大的多重條件選擇語(yǔ)句中,比直接繼承環(huán)境類的辦法還要原始和落后。
(3)策略模式提供了一種算法的復(fù)用機(jī)制。由于將算法單獨(dú)提取出來(lái)封裝在策略類中,因此不同的環(huán)境類可以方便地復(fù)用這些策略類。
缺點(diǎn):
(1)客戶端必須知道所有的策略類,并自行決定使用哪一個(gè)策略類。這就意味著客戶端必須理解這些算法的區(qū)別,以便適時(shí)選擇恰當(dāng)?shù)乃惴?。換言之,策略模式只適用于客戶端知道所有的算法或行為的情況。
(2)策略模式將造成系統(tǒng)產(chǎn)生很多具體策略類,任何細(xì)小的變化都將導(dǎo)致系統(tǒng)要增加一個(gè)新的具體策略類。
適用場(chǎng)景:
準(zhǔn)備一組算法,并將每一個(gè)算法封裝起來(lái),使得它們可以互換。
命令模式
將一個(gè)請(qǐng)求封裝為一個(gè)對(duì)象,從而讓我們可用不同的請(qǐng)求對(duì)客戶進(jìn)行參數(shù)化;對(duì)請(qǐng)求排隊(duì)或者記錄請(qǐng)求日志,以及支持可撤銷的操作。命令模式是一種對(duì)象行為型模式,其別名為動(dòng)作(Action)模式或事務(wù)(Transaction)模式。
命令模式可以將請(qǐng)求發(fā)送者和接收者完全解耦,發(fā)送者與接收者之間沒(méi)有直接引用關(guān)系,發(fā)送請(qǐng)求的對(duì)象只需要知道如何發(fā)送請(qǐng)求,而不必知道如何完成請(qǐng)求。

Command(抽象命令類):抽象命令類一般是一個(gè)抽象類或接口,在其中聲明了用于執(zhí)行請(qǐng)求的execute()等方法,通過(guò)這些方法可以調(diào)用請(qǐng)求接收者的相關(guān)操作。
ConcreteCommand(具體命令類):具體命令類是抽象命令類的子類,實(shí)現(xiàn)了在抽象命令類中聲明的方法,它對(duì)應(yīng)具體的接收者對(duì)象,將接收者對(duì)象的動(dòng)作綁定其中。在實(shí)現(xiàn)execute()方法時(shí),將調(diào)用接收者對(duì)象的相關(guān)操作(Action)。
Invoker(調(diào)用者):調(diào)用者即請(qǐng)求發(fā)送者,它通過(guò)命令對(duì)象來(lái)執(zhí)行請(qǐng)求。一個(gè)調(diào)用者并不需要在設(shè)計(jì)時(shí)確定其接收者,因此它只與抽象命令類之間存在關(guān)聯(lián)關(guān)系。在程序運(yùn)行時(shí)可以將一個(gè)具體命令對(duì)象注入其中,再調(diào)用具體命令對(duì)象的execute()方法,從而實(shí)現(xiàn)間接調(diào)用請(qǐng)求接收者的相關(guān)操作。
Receiver(接收者):接收者執(zhí)行與請(qǐng)求相關(guān)的操作,它具體實(shí)現(xiàn)對(duì)請(qǐng)求的業(yè)務(wù)處理。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include<queue>
using namespace std;
//協(xié)議處理類
class HandleClientProtocol{
public:
//處理增加金幣
void AddMoney(){
cout << "給玩家增加金幣!" << endl;
}
//處理增加鉆石
void AddDiamond(){
cout << "給玩家增加鉆石!" << endl;
}
//處理玩家裝備
void AddEquipment(){
cout << "給玩家穿裝備!" << endl;
}
//處理玩家升級(jí)
void addLevel(){
cout << "給玩家升級(jí)!" << endl;
}
};
//命令接口
class AbstractCommand{
public:
virtual void handle() = 0; //處理客戶端請(qǐng)求的接口
};
//處理增加金幣請(qǐng)求
class AddMoneyCommand :public AbstractCommand{
public:
AddMoneyCommand(HandleClientProtocol* protocol){
this->pProtocol = protocol;
}
virtual void handle(){
this->pProtocol->AddMoney();
}
public:
HandleClientProtocol* pProtocol;
};
//處理增加鉆石的請(qǐng)求
class AddDiamondCommand :public AbstractCommand{
public:
AddDiamondCommand(HandleClientProtocol* protocol){
this->pProtocol = protocol;
}
virtual void handle(){
this->pProtocol->AddDiamond();
}
public:
HandleClientProtocol* pProtocol;
};
//處理玩家穿裝備的請(qǐng)求
class AddEquipmentCommand : public AbstractCommand{
public:
AddEquipmentCommand(HandleClientProtocol* protocol){
this->pProtocol = protocol;
}
virtual void handle(){
this->pProtocol->AddEquipment();
}
public:
HandleClientProtocol* pProtocol;
};
//處理玩家升級(jí)的請(qǐng)求
class AddLevelCommand : public AbstractCommand{
public:
AddLevelCommand(HandleClientProtocol* protocol){
this->pProtocol = protocol;
}
virtual void handle(){
this->pProtocol->addLevel();
}
public:
HandleClientProtocol* pProtocol;
};
//服務(wù)器程序
class Serser{
public:
void addRequest(AbstractCommand* command){
mCommands.push(command);
}
void startHandle(){
while (!mCommands.empty()){
AbstractCommand* command = mCommands.front();
command->handle();
mCommands.pop();
}
}
public:
queue<AbstractCommand*> mCommands;
};
void test01(){
HandleClientProtocol* protocol = new HandleClientProtocol;
//客戶端增加金幣的請(qǐng)求
AbstractCommand* addmoney = new AddMoneyCommand(protocol);
//客戶端增加鉆石的請(qǐng)求
AbstractCommand* adddiamond = new AddDiamondCommand(protocol);
//客戶端穿裝備的請(qǐng)求
AbstractCommand* addequpment = new AddEquipmentCommand(protocol);
//客戶端升級(jí)請(qǐng)求
AbstractCommand* addlevel = new AddLevelCommand(protocol);
Serser* server = new Serser;
//將客戶端請(qǐng)求加入到處理的隊(duì)列中
server->addRequest(addmoney);
server->addRequest(adddiamond);
server->addRequest(addequpment);
server->addRequest(addlevel);
//服務(wù)器開(kāi)始處理請(qǐng)求
server->startHandle();
}
int main(void){
test01();
return 0;
}
命令模式的優(yōu)缺點(diǎn)及適用場(chǎng)景
優(yōu)點(diǎn):
(1)降低系統(tǒng)的耦合度。由于請(qǐng)求者與接收者之間不存在直接引用,因此請(qǐng)求者與接收者之間實(shí)現(xiàn)完全解耦,相同的請(qǐng)求者可以對(duì)應(yīng)不同的接收者,同樣,相同的接收者也可以供不同的請(qǐng)求者使用,兩者之間具有良好的獨(dú)立性。
(2)新的命令可以很容易地加入到系統(tǒng)中。由于增加新的具體命令類不會(huì)影響到其他類,因此增加新的具體命令類很容易,無(wú)須修改原有系統(tǒng)源代碼,甚至客戶類代碼,滿足“開(kāi)閉原則”的要求。
(3)可以比較容易地設(shè)計(jì)一個(gè)命令隊(duì)列或宏命令(組合命令)。
缺點(diǎn):
使用命令模式可能會(huì)導(dǎo)致某些系統(tǒng)有過(guò)多的具體命令類。因?yàn)獒槍?duì)每一個(gè)對(duì)請(qǐng)求接收者的調(diào)用操作都需要設(shè)計(jì)一個(gè)具體命令類,因此在某些系統(tǒng)中可能需要提供大量的具體命令類,這將影響命令模式的使用。
適用場(chǎng)景:
(1) 系統(tǒng)需要將請(qǐng)求調(diào)用者和請(qǐng)求接收者解耦,使得調(diào)用者和接收者不直接交互。請(qǐng)求調(diào)用者無(wú)須知道接收者的存在,也無(wú)須知道接收者是誰(shuí),接收者也無(wú)須關(guān)心何時(shí)被調(diào)用。
(2) 系統(tǒng)需要在不同的時(shí)間指定請(qǐng)求、將請(qǐng)求排隊(duì)和執(zhí)行請(qǐng)求。一個(gè)命令對(duì)象和請(qǐng)求的初始調(diào)用者可以有不同的生命期,換言之,最初的請(qǐng)求發(fā)出者可能已經(jīng)不在了,而命令對(duì)象本身仍然是活動(dòng)的,可以通過(guò)該命令對(duì)象去調(diào)用請(qǐng)求接收者,而無(wú)須關(guān)心請(qǐng)求調(diào)用者的存在性,可以通過(guò)請(qǐng)求日志文件等機(jī)制來(lái)具體實(shí)現(xiàn)。
(3) 系統(tǒng)需要將一組操作組合在一起形成宏命令。
觀察者模式
觀察者模式是用于建立一種對(duì)象與對(duì)象之間的依賴關(guān)系,一個(gè)對(duì)象發(fā)生改變時(shí)將自動(dòng)通知其他對(duì)象,其他對(duì)象將相應(yīng)作出反應(yīng)。在觀察者模式中,發(fā)生改變的對(duì)象稱為觀察目標(biāo),而被通知的對(duì)象稱為觀察者,一個(gè)觀察目標(biāo)可以對(duì)應(yīng)多個(gè)觀察者,而且這些觀察者之間可以沒(méi)有任何相互聯(lián)系,可以根據(jù)需要增加和刪除觀察者,使得系統(tǒng)更易于擴(kuò)展。

Subject(被觀察者或目標(biāo),抽象主題):被觀察的對(duì)象。當(dāng)需要被觀察的狀態(tài)發(fā)生變化時(shí),需要通知隊(duì)列中所有觀察者對(duì)象。Subject需要維持(添加,刪除,通知)一個(gè)觀察者對(duì)象的隊(duì)列列表。
ConcreteSubject(具體被觀察者或目標(biāo),具體主題):被觀察者的具體實(shí)現(xiàn)。包含一些基本的屬性狀態(tài)及其他操作。
Observer(觀察者):接口或抽象類。當(dāng)Subject的狀態(tài)發(fā)生變化時(shí),Observer對(duì)象將通過(guò)一個(gè)callback函數(shù)得到通知。
ConcreteObserver(具體觀察者):觀察者的具體實(shí)現(xiàn)。得到通知后將完成一些具體的業(yè)務(wù)邏輯處理。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include<list>
using namespace std;
//抽象的英雄 抽象的觀察者
class AbstractHero{
public:
virtual void Update() = 0;
};
//具體英雄 具體觀察者
class HeroA :public AbstractHero{
public:
HeroA(){
cout << "英雄A正在擼BOSS ..." << endl;
}
virtual void Update(){
cout << "英雄A停止擼,待機(jī)狀態(tài)..." << endl;
}
};
class HeroB :public AbstractHero{
public:
HeroB(){
cout << "英雄B正在擼BOSS ..." << endl;
}
virtual void Update(){
cout << "英雄B停止擼,待機(jī)狀態(tài)..." << endl;
}
};
class HeroC :public AbstractHero{
public:
HeroC(){
cout << "英雄C正在擼BOSS ..." << endl;
}
virtual void Update(){
cout << "英雄C停止擼,待機(jī)狀態(tài)..." << endl;
}
};
class HeroD :public AbstractHero{
public:
HeroD(){
cout << "英雄D正在擼BOSS ..." << endl;
}
virtual void Update(){
cout << "英雄D停止擼,待機(jī)狀態(tài)..." << endl;
}
};
class HeroE :public AbstractHero{
public:
HeroE(){
cout << "英雄E正在擼BOSS ..." << endl;
}
virtual void Update(){
cout << "英雄E停止擼,待機(jī)狀態(tài)..." << endl;
}
};
//觀察目標(biāo)抽象
class AbstractBoss{
public:
//添加觀察者
virtual void addHero(AbstractHero* hero) = 0;
//刪除觀察者
virtual void deleteHero(AbstractHero* hero) = 0;
//通知所有觀察者
virtual void notify() = 0;
};
//具體的觀察者 BOSSA
class BOSSA : public AbstractBoss{
public:
virtual void addHero(AbstractHero* hero){
pHeroList.push_back(hero);
}
//刪除觀察者
virtual void deleteHero(AbstractHero* hero){
pHeroList.remove(hero);
}
//通知所有觀察者
virtual void notify(){
for (list<AbstractHero*>::iterator it = pHeroList.begin(); it != pHeroList.end();it ++){
(*it)->Update();
}
}
public:
list<AbstractHero*> pHeroList;
};
void test01(){
//創(chuàng)建觀察者
AbstractHero* heroA = new HeroA;
AbstractHero* heroB = new HeroB;
AbstractHero* heroC = new HeroC;
AbstractHero* heroD = new HeroD;
AbstractHero* heroE = new HeroE;
//創(chuàng)建觀察目標(biāo)
AbstractBoss* bossA = new BOSSA;
bossA->addHero(heroA);
bossA->addHero(heroB);
bossA->addHero(heroC);
bossA->addHero(heroD);
bossA->addHero(heroE);
cout << "heroC陣亡..." << endl;
bossA->deleteHero(heroC);
cout << "Boss死了...通知其他英雄停止攻擊,搶裝備..." << endl;
bossA->notify();
}
int main(void){
test01();
return 0;
}
觀察者模式的優(yōu)缺點(diǎn)及適用場(chǎng)景
優(yōu)點(diǎn):
(1)觀察者模式可以實(shí)現(xiàn)表示層和數(shù)據(jù)邏輯層的分離,定義了穩(wěn)定的消息更新傳遞機(jī)制,并抽象了更新接口,使得可以有各種各樣不同的表示層充當(dāng)具體觀察者角色。
(2)觀察者模式在觀察目標(biāo)和觀察者之間建立一個(gè)抽象的耦合。觀察目標(biāo)只需要維持一個(gè)抽象觀察者的集合,無(wú)須了解其具體觀察者。由于觀察目標(biāo)和觀察者沒(méi)有緊密地耦合在一起,因此它們可以屬于不同的抽象化層次。
(3)觀察者模式支持廣播通信,觀察目標(biāo)會(huì)向所有已注冊(cè)的觀察者對(duì)象發(fā)送通知,簡(jiǎn)化了一對(duì)多系統(tǒng)設(shè)計(jì)的難度。
(4)觀察者模式滿足“開(kāi)閉原則”的要求,增加新的具體觀察者無(wú)須修改原有系統(tǒng)代碼,在具體觀察者與觀察目標(biāo)之間不存在關(guān)聯(lián)關(guān)系的情況下,增加新的觀察目標(biāo)也很方便。
缺點(diǎn):
(1)如果一個(gè)觀察目標(biāo)對(duì)象有很多直接和間接觀察者,將所有的觀察者都通知到會(huì)花費(fèi)很多時(shí)間。
(2)觀察者模式?jīng)]有相應(yīng)的機(jī)制讓觀察者知道所觀察的目標(biāo)對(duì)象是怎么發(fā)生變化的,而僅僅只是知道觀察目標(biāo)發(fā)生了變化。
適用場(chǎng)景:
(1)一個(gè)抽象模型有兩個(gè)方面,其中一個(gè)方面依賴于另一個(gè)方面,將這兩個(gè)方面封裝在獨(dú)立的對(duì)象中使它們可以各自獨(dú)立地改變和復(fù)用。
(2)一個(gè)對(duì)象的改變將導(dǎo)致一個(gè)或多個(gè)其他對(duì)象也發(fā)生改變,而并不知道具體有多少對(duì)象將發(fā)生改變,也不知道這些對(duì)象是誰(shuí)。
(3)需要在系統(tǒng)中創(chuàng)建一個(gè)觸發(fā)鏈,A對(duì)象的行為將影響B(tài)對(duì)象,B對(duì)象的行為將影響C對(duì)象……,可以使用觀察者模式創(chuàng)建一種鏈?zhǔn)接|發(fā)機(jī)制。