C++進階(語法篇)—第11章 設計模式(2)
11.3行為型模式
行為型模式:主要用於管理物件之間的演算法、關係和職責。主要講策略模式、命令模式、觀察者模式、模板模式。
11.3.1策略模式
策略模式:定義一系列演算法,將這些演算法封裝起來,並且使演算法之間可以轉換。本質是將演算法和客戶端之間隔離,使得客戶端只能通過抽象演算法類來訪問具體演算法。
假設手機需要支援3種使用模式,分別是標準模式、駕車模式、飛航模式。現在你是手機的開發者,該如何設計應用程式?如果將來手機還要支援靜音模式,又該如何設計?
#include <iostream>
using namespace
//模式:介面
class Mode
{
public:
virtual ~Mode(){}
virtual void UseMode(void) = 0;
};
//標準模式
class StandardMode:public Mode
{
public:
virtual void UseMode(void){cout<<"Standard Mode!"<<endl;};
};
//駕車模式
class DrivingMode:public
{
public:
virtual void UseMode(void){cout<<"Driving Mode!"<<endl;};
};
//飛航模式
class FlightMode:public Mode
{
public:
virtual void UseMode(void){cout<<"Flight Mode!"<<endl;};
};
//手機模式
class PhoneMode
{
private
Mode * mode;
public:
PhoneMode(Mode * mode)
{
this->mode = mode;
}
void UseMode()
{
mode->UseMode();
}
};
int main(int argc,char ** argv)
{
StandardMode * sm = new StandardMode;
DrivingMode * dm = new DrivingMode;
FlightMode * fm = new FlightMode;
PhoneMode pm1(sm);
PhoneMode pm2(dm);
PhoneMode pm3(fm);
pm1.UseMode();
pm2.UseMode();
pm3.UseMode();
delete sm;
delete dm;
delete fm;
return 0;
}
執行結果:
Standard Mode!
Driving Mode!
Flight Mode!
策略模式結構圖:
Context:環境角色,持有一個對Stratery的引用,最終給客戶端使用。相當於PhoneMode。
Stratery:抽象策略類,相當於Mode。
ConcreteStratery:具體策略類,相當於StandardMode、DrivingMode、FlightMode。
策略模式和簡單工廠模式看起來很相似,都是通過多型來實現不同子類的選取。簡單工廠模式是工廠根據需求來建立物件(產品),然後將事情交給物件去完成。策略模式是環境角色根據自己選擇的策略來建立物件,這個物件是其本身,因此所有的事情還是自己來完成。難以理解的話,可以看看模式結構圖。
11.3.2命令模式
餐館服務員接收到一份訂單:客戶要求先來一份烤肉再來一份炒菜(烤肉在前,炒菜在後);服務員接收到烤肉命令和炒菜命令,然後執行命令(但命令的真正實現不是服務員);廚師接收到烤肉命令和炒菜命令後,開始幹活。
//Receiver.h
#pragma once
#include <iostream>
using namespace std;
//廚師
class Cook
{
public:
//烤肉
void Barbecue(void)
{
cout << "Barbecue..." << endl;
}
//炒菜
void StirFry(void)
{
cout << "StirFry" << endl;
}
};
//Command.h
#pragma once
#include "Receiver.h"
class Command
{
public:
Command() {}
Command(Cook * cook)
{
this->cook = cook;
}
virtual void execute(void) = 0;
protected:
Cook * cook;
};
//烤肉命令
class BarbecueCommand :public Command
{
public:
BarbecueCommand() {}
BarbecueCommand(Cook * cook)
{
this->cook = cook;
}
void execute(void)
{
cout << "BarbecueCommand::execute" << endl;
cook->Barbecue();
}
};
class StirFryCommand :public Command
{
public:
StirFryCommand() {}
StirFryCommand(Cook * cook)
{
this->cook = cook;
}
void execute(void)
{
cout << "StirFryCommand::execute" << endl;
cook->StirFry();
}
};
//Invoker.h
#pragma once
#include "Command.h"
#include <list>
class Waiter
{
public:
Waiter() {};
// 新增命令
void addCmd(Command *cmd)
{
cmds.push_back(cmd);
}
// 刪除命令
void deleteCmd(Command *cmd)
{
cmds.remove(cmd);
}
// 執行命令
void notify()
{
for (list<Command *>::iterator it = cmds.begin(); it != cmds.end(); ++it)
{
(*it)->execute();
}
}
private:
std::list<Command *> cmds; // 命令佇列
};
//main.cpp
#include <iostream>
#include "Invoker.h"
#include "Receiver.h"
#include "Command.h"
using namespace std;
int main(int argc, char ** argv)
{
Cook * ck = new Cook;
BarbecueCommand * pBarCom = new BarbecueCommand(ck);
StirFryCommand * pStiCom = new StirFryCommand(ck);
Waiter wait;
wait.addCmd(pBarCom);
wait.addCmd(pStiCom);
wait.notify();
delete ck;
delete pBarCom;
delete pStiCom;
return 0;
}
執行結果:
BarbecueCommand::execute
Barbecue...
StirFryCommand::execute
StirFry
命令模式結構圖:
Invoker:命令的持有者和執行者;
Command:命令的抽象類;
ConcreteCommand:命令的具體類;
Receiver:命令的接收者和實際執行者;
命令模式難以理解,舉個實際例子:打車客戶(Client)發出打車命令->滴滴平臺(Invoker)接收到命令,然後發出打車命令->滴滴師傅(Receiver)接收到打車命令,然後去目標地點接人。通用例子:Client發出命令->Invoker持有,加入命令佇列,然後執行命令->Receiver接收和開始幹活。
11.3.3觀察者模式
觀察者模式:定義物件間一對多的依賴關係,當一個物件的狀態發生改變時,所有依賴它的物件得到通知並自動更新。
假設小明爸爸和小明媽媽關注小明的成績,當小明考試成績出來時,需要及時通知小明的父母,該如何設計這個程式?
#include <iostream>
#include <list>
using namespace std;
class Subject;
class Observer;
//抽象目標:Subject
class Subject
{
public:
virtual void Attach(Observer *) = 0;//註冊觀察者
virtual void Detach(Observer *) = 0;//登出觀察者
virtual void Notify() = 0;//通知觀察者
};
//抽象觀察者:Observer
class Observer
{
public:
virtual void Update(double) = 0;//更新狀態
};
//具體目標:ConcreteSubject
class Student : public Subject
{
private:
list<Observer *> pObserverList;//觀察者列表
double achievement;
public:
void Attach(Observer * pObserver)
{
pObserverList.push_back(pObserver);
}
void Detach(Observer * pObserver)
{
pObserverList.remove(pObserver);
}
void Notify()
{
for(list<Observer *>::iterator it = pObserverList.begin(); it != pObserverList.end(); ++it)
{
(*it)->Update(achievement);
}
}
void setValue(double achievement)
{
this->achievement = achievement;
}
};
//具體觀察者:ConcreteObserver
class Father :public Observer
{
private:
Subject * pSubject;
public:
Father() {}
Father(Subject * pSubject)
{
this->pSubject = pSubject;
}
void Update(double achievement)
{
cout <<"孩子成績:" << achievement << endl;
}
};
class Mother : public Observer
{
private:
Subject * pSubject;
public:
Mother() {}
Mother(Subject * pSubject)
{
this->pSubject = pSubject;
}
void Update(double achievement)
{
cout << "孩子成績:" << achievement << endl;
}
};
int main(int argc, char ** argv)
{
//建立具體目標
Student * xiaoming = new Student();
xiaoming->setValue(60);
//建立具體觀察者
Father * xmF = new Father(xiaoming);
Mother * xmM = new Mother(xiaoming);
//加入觀察佇列
xiaoming->Attach(xmF);
xiaoming->Attach(xmM);
//通知觀察者
xiaoming->Notify();
delete xiaoming;
delete xmF;
delete xmM;
return 0;
}
執行結果:
孩子成績:60
孩子成績:60
觀察者模式結構圖:
Subject(抽象目標):知道所有觀察者,並提供註冊和刪除觀察者的介面;
Observer(抽象觀察者):為具體觀察者提供介面,在得到目標的通知時進行自我更新。
ConcreteSubject(具體目標):當具體目標的狀態發生改變,通知所有觀察者。
ConcreteObserver(具體觀察者):實現更新介面Update。