模版方法模式
定義一個(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é)原則和開閉原則。
缺點(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ì)“開閉原則”的完美支持,用戶可以在不修改原有系統(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ù)乃惴ㄋ醣酢Q言之,策略模式只適用于客戶端知道所有的算法或行為的情況。
(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ā)送者與接收者之間沒有直接引用關(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ù)器開始處理請(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)源代碼,甚至客戶類代碼俱两,滿足“開閉原則”的要求饱狂。
(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è)觀察者,而且這些觀察者之間可以沒有任何相互聯(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)和觀察者沒有緊密地耦合在一起寺晌,因此它們可以屬于不同的抽象化層次。
(3)觀察者模式支持廣播通信码邻,觀察目標(biāo)會(huì)向所有已注冊(cè)的觀察者對(duì)象發(fā)送通知折剃,簡(jiǎn)化了一對(duì)多系統(tǒng)設(shè)計(jì)的難度。
(4)觀察者模式滿足“開閉原則”的要求像屋,增加新的具體觀察者無(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ī)制澎办。