背景
設計模式是來源於工業實踐的重要開發經驗,它實際上是面向對象的數據結構,掌握設計模式是掌握面向對象設計的根本要求。
原文:《C++ 常用設計模式》 (已經根據比較好的學習順序進行了排序)
1、工廠模式(Factory)
在工廠模式中,我們在創建對象時不會對客戶端暴露創建邏輯,並且是通過使用一個共同的接口來指向新創建的對象。工廠模式作為一種創建模式,一般在創建復雜對象時,考慮使用;在創建簡單對象時,建議直接new完成一個實例對象的創建。
1.1、簡單工廠模式
主要特點是需要在工廠類中做判斷,從而創造相應的產品,當增加新產品時,需要修改工廠類。使用簡單工廠模式,我們只需要知道具體的產品型號就可以創建一個產品。
缺點:工廠類集中了所有產品類的創建邏輯,如果產品量較大,會使得工廠類變的非常臃腫。
/*
關鍵代碼:創建過程在工廠類中完成。
*/
#include <iostream>
using namespace std;
//定義產品類型信息
typedef enum
{
Tank_Type_56,
Tank_Type_96,
Tank_Type_Num
}Tank_Type;
//抽象產品類
class Tank
{
public:
virtual const string& type() = 0;
};
//具體的產品類
class Tank56 : public Tank
{
public:
Tank56():Tank(),m_strType("Tank56")
{
}
// 在派生類的成員函數中使用override時,如果基類中無此函數,或基類中的函數並不是虛函數,編譯器會給出相關錯誤信息。
const string& type() override
{
cout << m_strType.data() << endl;
return m_strType;
}
private:
string m_strType;
};
//具體的產品類
class Tank96 : public Tank
{
public:
Tank96():Tank(),m_strType("Tank96")
{
}
const string& type() override
{
cout << m_strType.data() << endl;
return m_strType;
}
private:
string m_strType;
};
//工廠類
class TankFactory
{
public:
//根據產品信息創建具體的產品類實例,返回一個抽象產品類
Tank* createTank(Tank_Type type)
{
switch(type)
{
case Tank_Type_56:
return new Tank56();
case Tank_Type_96:
return new Tank96();
default:
return nullptr;
}
}
};
int main()
{
TankFactory* factory = new TankFactory();
Tank* tank56 = factory->createTank(Tank_Type_56);
tank56->type();
Tank* tank96 = factory->createTank(Tank_Type_96);
tank96->type();
delete tank96;
tank96 = nullptr;
delete tank56;
tank56 = nullptr;
delete factory;
factory = nullptr;
return 0;
}
1.2、工廠方法模式
定義一個創建對象的接口,其子類去具體現實這個接口以完成具體的創建工作。如果需要增加新的產品類,只需要擴展一個相應的工廠類即可。
缺點:產品類數據較多時,需要實現大量的工廠類,這無疑增加了代碼量。
/*
關鍵代碼:創建過程在其子類執行。
*/
#include <iostream>
using namespace std;
//產品抽象類
class Tank
{
public:
virtual const string& type() = 0;
};
//具體的產品類
class Tank56 : public Tank
{
public:
Tank56():Tank(),m_strType("Tank56")
{
}
const string& type() override
{
cout << m_strType.data() << endl;
return m_strType;
}
private:
string m_strType;
};
//具體的產品類
class Tank96 : public Tank
{
public:
Tank96():Tank(),m_strType("Tank96")
{
}
const string& type() override
{
cout << m_strType.data() << endl;
return m_strType;
}
private:
string m_strType;
};
//抽象工廠類,提供一個創建接口
class TankFactory
{
public:
//提供創建產品實例的接口,返回抽象產品類
virtual Tank* createTank() = 0;
};
//具體的創建工廠類,使用抽象工廠類提供的接口,去創建具體的產品實例
class Tank56Factory : public TankFactory
{
public:
Tank* createTank() override
{
return new Tank56();
}
};
//具體的創建工廠類,使用抽象工廠類提供的接口,去創建具體的產品實例
class Tank96Factory : public TankFactory
{
public:
Tank* createTank() override
{
return new Tank96();
}
};
int main()
{
TankFactory* factory56 = new Tank56Factory();
Tank* tank56 = factory56->createTank();
tank56->type();
TankFactory* factory96 = new Tank96Factory();
Tank* tank96 = factory96->createTank();
tank96->type();
delete tank96;
tank96 = nullptr;
delete factory96;
factory96 = nullptr;
delete tank56;
tank56 = nullptr;
delete factory56;
factory56 = nullptr;
return 0;
}
1.3、抽象工廠模式
抽象工廠模式提供創建一系列相關或相互依賴對象的接口,而無需指定它們具體的類。
當存在多個產品系列,而客戶端只使用一個系列的產品時,可以考慮使用抽象工廠模式。
缺點:當增加一個新系列的產品時,不僅需要現實具體的產品類,還需要增加一個新的創建接口,擴展相對困難。
/*
* 關鍵代碼:在一個工廠里聚合多個同類產品。
* 以下代碼以白色衣服和黑色衣服為例,白色衣服為一個產品系列,黑色衣服為一個產品系列。白色上衣搭配白色褲子, 黑色上衣搭配黑色褲字。每個系列的衣服由一個對應的工廠創建,這樣一個工廠創建的衣服能保證衣服為同一個系列。
*/
//抽象上衣類
class Coat
{
public:
virtual const string& color() = 0;
};
//黑色上衣類
class BlackCoat : public Coat
{
public:
BlackCoat():Coat(),m_strColor("Black Coat")
{
}
const string& color() override
{
cout << m_strColor.data() << endl;
return m_strColor;
}
private:
string m_strColor;
};
//白色上衣類
class WhiteCoat : public Coat
{
public:
WhiteCoat():Coat(),m_strColor("White Coat")
{
}
const string& color() override
{
cout << m_strColor.data() << endl;
return m_strColor;
}
private:
string m_strColor;
};
//抽象褲子類
class Pants
{
public:
virtual const string& color() = 0;
};
//黑色褲子類
class BlackPants : public Pants
{
public:
BlackPants():Pants(),m_strColor("Black Pants")
{
}
const string& color() override
{
cout << m_strColor.data() << endl;
return m_strColor;
}
private:
string m_strColor;
};
//白色褲子類
class WhitePants : public Pants
{
public:
WhitePants():Pants(),m_strColor("White Pants")
{
}
const string& color() override
{
cout << m_strColor.data() << endl;
return m_strColor;
}
private:
string m_strColor;
};
//抽象工廠類,提供衣服創建接口
class Factory
{
public:
//上衣創建接口,返回抽象上衣類
virtual Coat* createCoat() = 0;
//褲子創建接口,返回抽象褲子類
virtual Pants* createPants() = 0;
};
//創建白色衣服的工廠類,具體實現創建白色上衣和白色褲子的接口
class WhiteFactory : public Factory
{
public:
Coat* createCoat() override
{
return new WhiteCoat();
}
Pants* createPants() override
{
return new WhitePants();
}
};
//創建黑色衣服的工廠類,具體實現創建黑色上衣和白色褲子的接口
class BlackFactory : public Factory
{
Coat* createCoat() override
{
return new BlackCoat();
}
Pants* createPants() override
{
return new BlackPants();
}
};
2、單例模式(Singleton)
單例模式顧名思義,保證一個類僅可以有一個實例化對象,並且提供一個可以訪問它的全局接口。實現單例模式必須注意一下幾點:
- 單例類只能由一個實例化對象。
- 單例類必須自己提供一個實例化對象。
- 單例類必須提供一個可以訪問唯一實例化對象的接口。
單例模式分為懶漢和餓漢兩種實現方式。
2.1、懶漢單例模式
懶漢:故名思義,不到萬不得已就不會去實例化類,也就是說在第一次用到類實例的時候才會去實例化一個對象。在訪問量較小,甚至可能不會去訪問的情況下,采用懶漢實現,這是以時間換空間。
2.1.1、非線程安全的懶漢單例模式
/*
* 關鍵代碼:構造函數是私有的,不能通過賦值運算,拷貝構造等方式實例化對象。
*/
//懶漢式一般實現:非線程安全,getInstance返回的實例指針需要delete
class Singleton
{
public:
static Singleton* getInstance();
~Singleton(){}
private:
Singleton(){} //構造函數私有
Singleton(const Singleton& obj) = delete; //明確拒絕
Singleton& operator=(const Singleton& obj) = delete; //明確拒絕
static Singleton* m_pSingleton; // 靜態(static)成員: 不是任意對象的組成部分,但由給定類的全體對象所共享的數據成員或函數成員。
};
Singleton* Singleton::m_pSingleton = NULL;
Singleton* Singleton::getInstance()
{
if(m_pSingleton == NULL)
{
m_pSingleton = new Singleton;
}
return m_pSingleton;
}
2.1.2、線程安全的懶漢單例模式
std::mutex mt;
class Singleton
{
public:
static Singleton* getInstance();
private:
Singleton(){} //構造函數私有
Singleton(const Singleton&) = delete; //明確拒絕
Singleton& operator=(const Singleton&) = delete; //明確拒絕
static Singleton* m_pSingleton;
};
Singleton* Singleton::m_pSingleton = NULL;
Singleton* Singleton::getInstance()
{
if(m_pSingleton == NULL)
{
mt.lock();
if(m_pSingleton == NULL)
{
m_pSingleton = new Singleton();
}
mt.unlock();
}
return m_pSingleton;
}
2.1.3、返回一個reference指向local static對象
這種單例模式實現方式多線程可能存在不確定性:任何一種non-const static對象,不論它是local或non-local,在多線程環境下“等待某事發生”都會有麻煩。解決的方法:在程序的單線程啟動階段手工調用所有reference-returning函數。這種實現方式的好處是不需要去delete它。
class Singleton
{
public:
static Singleton& getInstance();
private:
Singleton(){}
Singleton(const Singleton&) = delete; //明確拒絕
Singleton& operator=(const Singleton&) = delete; //明確拒絕
};
Singleton& Singleton::getInstance()
{
static Singleton singleton;
return singleton;
}
2.2、餓漢單例模式
餓漢:餓了肯定要飢不擇食。所以在單例類定義的時候就進行實例化。在訪問量比較大,或者可能訪問的線程比較多時,采用餓漢實現,可以實現更好的性能。這是以空間換時間。
//餓漢式:線程安全,注意一定要在合適的地方去delete它
class Singleton
{
public:
static Singleton* getInstance();
private:
Singleton(){} //構造函數私有
Singleton(const Singleton&) = delete; //明確拒絕
Singleton& operator=(const Singleton&) = delete; //明確拒絕
static Singleton* m_pSingleton;
};
Singleton* Singleton::m_pSingleton = new Singleton();
Singleton* Singleton::getInstance()
{
return m_pSingleton;
}
3、外觀模式(Facade)
外觀模式:為子系統中的一組接口定義一個一致的界面;外觀模式提供一個高層的接口,這個接口使得這一子系統更加容易被使用;對於復雜的系統,系統為客戶端提供一個簡單的接口,把負責的實現過程封裝起來,客戶端不需要連接系統內部的細節。
以下情形建議考慮外觀模式:
- 設計初期階段,應有意識的將不同層分離,層與層之間建立外觀模式。
- 開發階段,子系統越來越復雜,使用外觀模式提供一個簡單的調用接口。
- 一個系統可能已經非常難易維護和擴展,但又包含了非常重要的功能,可以為其開發一個外觀類,使得新系統可以方便的與其交互。
優點:
- 實現了子系統與客戶端之間的松耦合關系。
- 客戶端屏蔽了子系統組件,減少了客戶端所需要處理的對象數據,使得子系統使用起來更方便容易。
- 更好的划分了設計層次,對於后期維護更加的容易。
/*
* 關鍵代碼:客戶與系統之間加一個外觀層,外觀層處理系統的調用關系、依賴關系等。
*以下實例以電腦的啟動過程為例,客戶端只關心電腦開機的、關機的過程,並不需要了解電腦內部子系統的啟動過程。
*/
#include <iostream>
using namespace std;
//抽象控件類,提供接口
class Control
{
public:
virtual void start() = 0;
virtual void shutdown() = 0;
};
//子控件, 主機
class Host : public Control
{
public:
void start() override
{
cout << "Host start" << endl;
}
void shutdown() override
{
cout << "Host shutdown" << endl;
}
};
//子控件, 顯示屏
class LCDDisplay : public Control
{
public:
void start() override
{
cout << "LCD Display start" << endl;
}
void shutdown() override
{
cout << "LCD Display shutdonw" << endl;
}
};
//子控件, 外部設備
class Peripheral : public Control
{
public:
void start() override
{
cout << "Peripheral start" << endl;
}
void shutdown() override
{
cout << "Peripheral shutdown" << endl;
}
};
class Computer
{
public:
void start()
{
m_host.start();
m_display.start();
m_peripheral.start();
cout << "Computer start" << endl;
}
void shutdown()
{
m_host.shutdown();
m_display.shutdown();
m_peripheral.shutdown();
cout << "Computer shutdown" << endl;
}
private:
Host m_host;
LCDDisplay m_display;
Peripheral m_peripheral;
};
int main()
{
Computer computer;
computer.start();
//do something
computer.shutdown();
return 0;
}
4、模板模式(Template)
模板模式:定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。
當多個類有相同的方法,並且邏輯相同,只是細節上有差異時,可以考慮使用模板模式。具體的實現上可以將相同的核心算法設計為模板方法,具體的實現細節有子類實現。
缺點:每一個不同的實現都需要一個子類來實現,導致類的個數增加,使得系統更加龐大。
以生產電腦為例,電腦生產的過程都是一樣的,只是一些裝配的器件可能不同而已。
/*
* 關鍵代碼:在抽象類實現通用接口,細節變化在子類實現。
*/
#include <iostream>
using namespace std;
class Computer
{
public:
void product()
{
installCpu();
installRam();
installGraphicsCard();
}
protected:
virtual void installCpu() = 0;
virtual void installRam() = 0;
virtual void installGraphicsCard() = 0;
};
class ComputerA : public Computer
{
protected:
void installCpu() override
{
cout << "ComputerA install Inter Core i5" << endl;
}
void installRam() override
{
cout << "ComputerA install 2G Ram" << endl;
}
void installGraphicsCard() override
{
cout << "ComputerA install Gtx940 GraphicsCard" << endl;
}
};
class ComputerB : public Computer
{
protected:
void installCpu() override
{
cout << "ComputerB install Inter Core i7" << endl;
}
void installRam() override
{
cout << "ComputerB install 4G Ram" << endl;
}
void installGraphicsCard() override
{
cout << "ComputerB install Gtx960 GraphicsCard" << endl;
}
};
int main()
{
ComputerB* c1 = new ComputerB();
c1->product();
delete c1;
c1 = nullptr;
return 0;
}
5、組合模式(Composite)
組合模式:將對象組合成樹形結構以表示“部分-整體”的層次結構,組合模式使得客戶端對單個對象和組合對象的使用具有一直性。
既然講到以樹形結構表示“部分-整體”,那可以將組合模式想象成一根大樹,將大樹分成樹枝和樹葉兩部分,樹枝上可以再長樹枝,也可以長樹葉,樹葉上則不能再長出別的東西。
以下情況可以考慮使用組合模式:
- 希望表示對象的部分-整體層次結構。
- 希望客戶端忽略組合對象與單個對象的不同,客戶端將統一的使用組合結構中的所有對象。
/*
* 關鍵代碼:樹枝內部組合該接口,並且含有內部屬性list,里面放Component。
*/
#include <iostream>
#include <list>
#include <memory>
using namespace std;
//抽象類,提供組合和單個對象的一致接口
class Company
{
public:
Company(const string& name): m_name(name){}
virtual ~Company(){ cout << "~Company()" << endl;}
virtual void add(Company* ) = 0;
virtual void remove(const string&) = 0;
virtual void display(int depth) = 0;
virtual const string& name()
{
return m_name;
}
protected:
string m_name;
};
//具體的單個對象實現類,“樹枝”類
class HeadCompany : public Company
{
public:
HeadCompany(const string& name): Company(name){}
virtual ~HeadCompany(){ cout << "~HeadCompany()" << endl;}
void add(Company* company) override
{
shared_ptr<Company> temp(company);
m_companyList.push_back(temp);
}
void remove(const string& strName) override
{
list<shared_ptr<Company>>::iterator iter = m_companyList.begin();
for(; iter != m_companyList.end(); iter++)
{
if((*iter).get()->name() == strName)
{
//不應該在此處使用list<T>.erase(list<T>::iterator iter),會導致iter++錯誤,這里刪除目 標元素之后,必須return。
m_companyList.erase(iter);
return;
}
}
}
void display(int depth) override
{
for(int i = 0; i < depth; i++)
{
cout << "-";
}
cout << this->name().data() << endl;
list<shared_ptr<Company>>::iterator iter = m_companyList.begin();
for(; iter!= m_companyList.end(); iter++)
{
(*iter).get()->display(depth + 1);
}
}
private:
list<shared_ptr<Company>> m_companyList;
};
//具體的單個對象實現類,“樹葉”類
class ResearchCompany : public Company
{
public:
ResearchCompany(const string& name): Company(name){}
virtual ~ResearchCompany(){ cout << "~ResearchCompany()" << endl;}
void add(Company* ) override
{
}
void remove(const string&) override
{
}
void display(int depth) override
{
for(int i = 0; i < depth; i++)
{
cout << "-";
}
cout << m_name.data() << endl;
}
};
//具體的單個對象實現類,“樹葉”類
class SalesCompany : public Company
{
public:
SalesCompany(const string& name): Company(name){}
virtual ~SalesCompany(){ cout << "~SalesCompany()" << endl;}
void add(Company* ) override
{
}
void remove(const string&) override
{
}
void display(int depth) override
{
for(int i = 0; i < depth; i++)
{
cout << "-";
}
cout << m_name.data() << endl;
}
};
//具體的單個對象實現類,“樹葉”類
class FinanceCompany : public Company
{
public:
FinanceCompany(const string& name): Company(name){}
virtual ~FinanceCompany(){ cout << "~FinanceCompany()" << endl;}
void add(Company* ) override
{
}
void remove(const string&) override
{
}
void display(int depth) override
{
for(int i = 0; i < depth; i++)
{
cout << "-";
}
cout << m_name.data() << endl;
}
};
int main()
{
HeadCompany* headRoot = new HeadCompany("Head Root Company");
HeadCompany* childRoot1 = new HeadCompany("Child Company A");
ResearchCompany* r1 = new ResearchCompany("Research Company A");
SalesCompany* s1 = new SalesCompany("Sales Company A");
SalesCompany* s2 = new SalesCompany("Sales Company B");
FinanceCompany* f1 = new FinanceCompany("FinanceCompany A");
childRoot1->add(r1);
childRoot1->add(s1);
childRoot1->add(s2);
childRoot1->add(f1);
HeadCompany* childRoot2 = new HeadCompany("Child Company B");
ResearchCompany* r2 = new ResearchCompany("Research Company B");
SalesCompany* s3 = new SalesCompany("Sales Company C");
SalesCompany* s4 = new SalesCompany("Sales Company D");
FinanceCompany* f2 = new FinanceCompany("FinanceCompany B");
childRoot2->add(r2);
childRoot2->add(s3);
childRoot2->add(s4);
childRoot2->add(f2);
headRoot->add(childRoot1);
headRoot->add(childRoot2);
headRoot->display(1);
cout << "\n***************\n" << endl;
childRoot1->remove("Sales Company B");
headRoot->display(1);
cout << "\n***************\n" << endl;
delete headRoot;
headRoot = nullptr;
return 0;
}
10、代理模式
代理模式:為其它對象提供一種代理以控制這個對象的訪問。在某些情況下,一個對象不適合或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介作用。
優點:
- 職責清晰。真實的角色只負責實現實際的業務邏輯,不用關心其它非本職責的事務,通過后期的代理完成具體的任務。這樣代碼會簡潔清晰。
- 代理對象可以在客戶端和目標對象之間起到中介的作用,這樣就保護了目標對象。
- 擴展性好。
/*
* 關鍵代碼:一個是真正的你要訪問的對象(目標類),一個是代理對象,真正對象與代理對象實現同一個接口,先訪問代理* 類再訪問真正要訪問的對象。
*/
#include <iostream>
using namespace std;
class Gril
{
public:
Gril(const string& name = "gril"):m_string(name){}
string getName()
{
return m_string;
}
private:
string m_string;
};
class Profession
{
public:
virtual ~Profession(){}
virtual void profess() = 0;
};
class YoungMan : public Profession
{
public:
YoungMan(const Gril& gril):m_gril(gril){}
void profess()
{
cout << "Young man love " << m_gril.getName().data() << endl;
}
private:
Gril m_gril;
};
class ManProxy : public Profession
{
public:
ManProxy(const Gril& gril):m_pMan(new YoungMan(gril)){}
~ManProxy()
{
delete m_pMan;
m_pMan = nullptr;
}
void profess()
{
m_pMan->profess();
}
private:
YoungMan* m_pMan;
};
int main(int argc, char *argv[])
{
Gril gril("heihei");
ManProxy* proxy = new ManProxy(gril);
proxy->profess();
delete proxy;
proxy = nullptr;
return 0;
}
6、觀察者模式(Observer)
觀察者模式:定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴於它的對象都要得到通知並自動更新。
觀察者模式從根本上講必須包含兩個角色:觀察者和被觀察對象。
- 被觀察對象自身應該包含一個容器來存放觀察者對象,當被觀察者自身發生改變時通知容器內所有的觀察者對象自動更新。
- 觀察者對象可以注冊到被觀察者的中,完成注冊后可以檢測被觀察者的變化,接收被觀察者的通知。當然觀察者也可以被注銷掉,停止對被觀察者的監控。
/*
* 關鍵代碼:在目標類中增加一個ArrayList來存放觀察者們。
*/
#include <iostream>
#include <list>
#include <memory>
using namespace std;
class View;
//被觀察者抽象類 數據模型
class DataModel
{
public:
virtual ~DataModel(){}
virtual void addView(View* view) = 0;
virtual void removeView(View* view) = 0;
virtual void notify() = 0; //通知函數
};
//觀察者抽象類 視圖
class View
{
public:
virtual ~View(){ cout << "~View()" << endl; }
virtual void update() = 0;
virtual void setViewName(const string& name) = 0;
virtual const string& name() = 0;
};
//具體的被觀察類, 整數模型
class IntDataModel:public DataModel
{
public:
~IntDataModel()
{
m_pViewList.clear();
}
virtual void addView(View* view) override
{
shared_ptr<View> temp(view);
auto iter = find(m_pViewList.begin(), m_pViewList.end(), temp);
if(iter == m_pViewList.end())
{
m_pViewList.push_front(temp);
}
else
{
cout << "View already exists" << endl;
}
}
void removeView(View* view) override
{
auto iter = m_pViewList.begin();
for(; iter != m_pViewList.end(); iter++)
{
if((*iter).get() == view)
{
m_pViewList.erase(iter);
cout << "remove view" << endl;
return;
}
}
}
virtual void notify() override
{
auto iter = m_pViewList.begin();
for(; iter != m_pViewList.end(); iter++)
{
(*iter).get()->update();
}
}
private:
list<shared_ptr<View>> m_pViewList;
};
//具體的觀察者類 表視圖
class TableView : public View
{
public:
TableView() : m_name("unknow"){}
TableView(const string& name) : m_name(name){}
~TableView(){ cout << "~TableView(): " << m_name.data() << endl; }
void setViewName(const string& name)
{
m_name = name;
}
const string& name()
{
return m_name;
}
void update() override
{
cout << m_name.data() << " update" << endl;
}
private:
string m_name;
};
int main()
{
/*
* 這里需要補充說明的是在此示例代碼中,View一旦被注冊到DataModel類之后,DataModel解析時會自動解析掉 * 內部容器中存儲的View對象,因此注冊后的View對象不需要在手動去delete,再去delete View對象會出錯。
*/
View* v1 = new TableView("TableView1");
View* v2 = new TableView("TableView2");
View* v3 = new TableView("TableView3");
View* v4 = new TableView("TableView4");
IntDataModel* model = new IntDataModel;
model->addView(v1);
model->addView(v2);
model->addView(v3);
model->addView(v4);
model->notify();
cout << "-------------\n" << endl;
model->removeView(v1);
model->notify();
delete model;
model = nullptr;
return 0;
}
7、策略模式(Strategy)
策略模式是指定義一系列的算法,把它們單獨封裝起來,並且使它們可以互相替換,使得算法可以獨立於使用它的客戶端而變化,也是說這些算法所完成的功能類型是一樣的,對外接口也是一樣的,只是不同的策略為引起環境角色環境角色表現出不同的行為。
相比於使用大量的if...else,使用策略模式可以降低復雜度,使得代碼更容易維護。
缺點:可能需要定義大量的策略類,並且這些策略類都要提供給客戶端。
[環境角色] 持有一個策略類的引用,最終給客戶端調用。
2.1、傳統的策略模式實現
/*
* 關鍵代碼:實現同一個接口。
* 以下代碼實例中,以游戲角色不同的攻擊方式為不同的策略,游戲角色即為執行不同策略的環境角色。
*/
#include <iostream>
using namespace std;
//抽象策略類,提供一個接口
class Hurt
{
public:
virtual void blood() = 0;
};
//具體的策略實現類,具體實現接口, Adc持續普通攻擊
class AdcHurt : public Hurt
{
public:
void blood() override
{
cout << "Adc hurt, Blood loss" << endl;
}
};
//具體的策略實現類,具體實現接口, Apc技能攻擊
class ApcHurt : public Hurt
{
public:
void blood() override
{
cout << "Apc Hurt, Blood loss" << endl;
}
};
//環境角色類, 游戲角色戰士,傳入一個策略類指針參數。
class Soldier
{
public:
Soldier(Hurt* hurt):m_pHurt(hurt)
{
}
//在不同的策略下,該游戲角色表現出不同的攻擊
void attack()
{
m_pHurt->blood();
}
private:
Hurt* m_pHurt;
};
//定義策略標簽
typedef enum
{
Hurt_Type_Adc,
Hurt_Type_Apc,
Hurt_Type_Num
}HurtType;
//環境角色類, 游戲角色法師,傳入一個策略標簽參數。
class Mage
{
public:
Mage(HurtType type)
{
switch(type)
{
case Hurt_Type_Adc:
m_pHurt = new AdcHurt();
break;
case Hurt_Type_Apc:
m_pHurt = new ApcHurt();
break;
default:
break;
}
}
~Mage()
{
delete m_pHurt;
m_pHurt = nullptr;
cout << "~Mage()" << endl;
}
void attack()
{
m_pHurt->blood();
}
private:
Hurt* m_pHurt;
};
//環境角色類, 游戲角色弓箭手,實現模板傳遞策略。
template<typename T>
class Archer
{
public:
void attack()
{
m_hurt.blood();
}
private:
T m_hurt;
};
int main()
{
Archer<ApcHurt>* arc = new Archer<ApcHurt>;
arc->attack();
delete arc;
arc = nullptr;
return 0;
}
2.2、使用函數指針實現策略模式
#include <iostream>
#include <functional>
void adcHurt()
{
std::cout << "Adc Hurt" << std::endl;
}
void apcHurt()
{
std::cout << "Apc Hurt" << std::endl;
}
//環境角色類, 使用傳統的函數指針
class Soldier
{
public:
typedef void (*Function)();
Soldier(Function fun): m_fun(fun)
{
}
void attack()
{
m_fun();
}
private:
Function m_fun;
};
//環境角色類, 使用std::function<>
class Mage
{
public:
typedef std::function<void()> Function;
Mage(Function fun): m_fun(fun)
{
}
void attack()
{
m_fun();
}
private:
Function m_fun;
};
int main()
{
Soldier* soldier = new Soldier(apcHurt);
soldier->attack();
delete soldier;
soldier = nullptr;
return 0;
}
8、建造者模式(Builder)
建造者模式:將復雜對象的構建和其表示分離,使得相同的構建過程可以產生不同的表示。
以下情形可以考慮使用建造者模式:
- 對象的創建復雜,但是其各個部分的子對象創建算法一定。
- 需求變化大,構造復雜對象的子對象經常變化,但將其組合在一起的算法相對穩定。
建造者模式的優點:
- 將對象的創建和表示分離,客戶端不需要了解具體的構建細節。
- 增加新的產品對象時,只需要增加其具體的建造類即可,不需要修改原來的代碼,擴展方便。
產品之間差異性大,內部變化較大、較復雜時不建議使用建造者模式。
/*
*關鍵代碼:建造者類:創建和提供實例; Director類:管理建造出來的實例的依賴關系。
*/
#include <iostream>
#include <string>
using namespace std;
//具體的產品類
class Order
{
public:
void setFood(const string& food)
{
m_strFood = food;
}
const string& food()
{
cout << m_strFood.data() << endl;
return m_strFood;
}
void setDrink(const string& drink)
{
m_strDrink = drink;
}
const string& drink()
{
cout << m_strDrink << endl;
return m_strDrink;
}
private:
string m_strFood;
string m_strDrink;
};
//抽象建造類,提供建造接口。
class OrderBuilder
{
public:
virtual ~OrderBuilder()
{
cout << "~OrderBuilder()" << endl;
}
virtual void setOrderFood() = 0;
virtual void setOrderDrink() = 0;
virtual Order* getOrder() = 0;
};
//具體的建造類
class VegetarianOrderBuilder : public OrderBuilder
{
public:
VegetarianOrderBuilder()
{
m_pOrder = new Order;
}
~VegetarianOrderBuilder()
{
cout << "~VegetarianOrderBuilder()" << endl;
delete m_pOrder;
m_pOrder = nullptr;
}
void setOrderFood() override
{
m_pOrder->setFood("vegetable salad");
}
void setOrderDrink() override
{
m_pOrder->setDrink("water");
}
Order* getOrder() override
{
return m_pOrder;
}
private:
Order* m_pOrder;
};
//具體的建造類
class MeatOrderBuilder : public OrderBuilder
{
public:
MeatOrderBuilder()
{
m_pOrder = new Order;
}
~MeatOrderBuilder()
{
cout << "~MeatOrderBuilder()" << endl;
delete m_pOrder;
m_pOrder = nullptr;
}
void setOrderFood() override
{
m_pOrder->setFood("beef");
}
void setOrderDrink() override
{
m_pOrder->setDrink("beer");
}
Order* getOrder() override
{
return m_pOrder;
}
private:
Order* m_pOrder;
};
//Director類,負責管理實例創建的依賴關系,指揮構建者類創建實例
class Director
{
public:
Director(OrderBuilder* builder) : m_pOrderBuilder(builder)
{
}
void construct()
{
m_pOrderBuilder->setOrderFood();
m_pOrderBuilder->setOrderDrink();
}
private:
OrderBuilder* m_pOrderBuilder;
};
int main()
{
// MeatOrderBuilder* mBuilder = new MeatOrderBuilder;
OrderBuilder* mBuilder = new MeatOrderBuilder; //注意抽象構建類必須有虛析構函數,解析時才會 調用子類的析構函數
Director* director = new Director(mBuilder);
director->construct();
Order* order = mBuilder->getOrder();
order->food();
order->drink();
delete director;
director = nullptr;
delete mBuilder;
mBuilder = nullptr;
return 0;
}
9、適配器模式(Adapter)
適配器模式可以將一個類的接口轉換成客戶端希望的另一個接口,使得原來由於接口不兼容而不能在一起工作的那些類可以在一起工作。通俗的講就是當我們已經有了一些類,而這些類不能滿足新的需求,此時就可以考慮是否能將現有的類適配成可以滿足新需求的類。適配器類需要繼承或依賴已有的類,實現想要的目標接口。
缺點:過多地使用適配器,會讓系統非常零亂,不易整體進行把握。比如,明明看到調用的是 A 接口,其實內部被適配成了 B 接口的實現,一個系統如果太多出現這種情況,無異於一場災難。因此如果不是很有必要,可以不使用適配器,而是直接對系統進行重構。
3.1、使用復合實現適配器模式
/*
* 關鍵代碼:適配器繼承或依賴已有的對象,實現想要的目標接口。
* 以下示例中,假設我們之前有了一個雙端隊列,新的需求要求使用棧和隊列來完成。
雙端隊列可以在頭尾刪減或增加元素。而棧是一種先進后出的數據結構,添加數據時添加到棧的頂部,刪除數據時先刪 除棧頂部的數據。因此我們完全可以將一個現有的雙端隊列適配成一個棧。
*/
//雙端隊列, 被適配類
class Deque
{
public:
void push_back(int x)
{
cout << "Deque push_back:" << x << endl;
}
void push_front(int x)
{
cout << "Deque push_front:" << x << endl;
}
void pop_back()
{
cout << "Deque pop_back" << endl;
}
void pop_front()
{
cout << "Deque pop_front" << endl;
}
};
//順序類,抽象目標類
class Sequence
{
public:
virtual void push(int x) = 0;
virtual void pop() = 0;
};
//棧,后進先出, 適配類
class Stack:public Sequence
{
public:
//將元素添加到堆棧的頂部。
void push(int x) override
{
m_deque.push_front(x);
}
//從堆棧中刪除頂部元素
void pop() override
{
m_deque.pop_front();
}
private:
Deque m_deque;
};
//隊列,先進先出,適配類
class Queue:public Sequence
{
public:
//將元素添加到隊列尾部
void push(int x) override
{
m_deque.push_back(x);
}
//從隊列中刪除頂部元素
void pop() override
{
m_deque.pop_front();
}
private:
Deque m_deque;
};
3.2、使用繼承實現適配器模式
//雙端隊列,被適配類
class Deque
{
public:
void push_back(int x)
{
cout << "Deque push_back:" << x << endl;
}
void push_front(int x)
{
cout << "Deque push_front:" << x << endl;
}
void pop_back()
{
cout << "Deque pop_back" << endl;
}
void pop_front()
{
cout << "Deque pop_front" << endl;
}
};
//順序類,抽象目標類
class Sequence
{
public:
virtual void push(int x) = 0;
virtual void pop() = 0;
};
//棧,后進先出, 適配類
class Stack:public Sequence, private Deque
{
public:
void push(int x)
{
push_front(x);
}
void pop()
{
pop_front();
}
};
//隊列,先進先出,適配類
class Queue:public Sequence, private Deque
{
public:
void push(int x)
{
push_back(x);
}
void pop()
{
pop_front();
}
};
10、橋接模式(Bridge)
橋接模式:將抽象部分與實現部分分離,使它們都可以獨立變換。
以下情形考慮使用橋接模式:
- 當一個對象有多個變化因素的時候,考慮依賴於抽象的實現,而不是具體的實現。
- 當多個變化因素在多個對象間共享時,考慮將這部分變化的部分抽象出來再聚合/合成進來。
- 當一個對象的多個變化因素可以動態變化的時候。
優點:
- 將實現抽離出來,再實現抽象,使得對象的具體實現依賴於抽象,滿足了依賴倒轉原則。
- 更好的可擴展性。
- 可動態的切換實現。橋接模式實現了抽象和實現的分離,在實現橋接模式時,就可以實現動態的選擇具體的實現。
/*
* 關鍵代碼:將現實獨立出來,抽象類依賴現實類。
* 以下示例中,將各類App、各類手機獨立開來,實現各種App和各種手機的自由橋接。
*/
#include <iostream>
using namespace std;
//抽象App類,提供接口
class App
{
public:
virtual ~App(){ cout << "~App()" << endl; }
virtual void run() = 0;
};
//具體的App實現類
class GameApp:public App
{
public:
void run()
{
cout << "GameApp Running" << endl;
}
};
//具體的App實現類
class TranslateApp:public App
{
public:
void run()
{
cout << "TranslateApp Running" << endl;
}
};
//抽象手機類,提供接口
class MobilePhone
{
public:
virtual ~MobilePhone(){ cout << "~MobilePhone()" << endl;}
virtual void appRun(App* app) = 0; //實現App與手機的橋接
};
//具體的手機實現類
class XiaoMi:public MobilePhone
{
public:
void appRun(App* app)
{
cout << "XiaoMi: ";
app->run();
}
};
//具體的手機實現類
class HuaWei:public MobilePhone
{
public:
void appRun(App* app)
{
cout << "HuaWei: ";
app->run();
}
};
int main()
{
App* gameApp = new GameApp;
App* translateApp = new TranslateApp;
MobilePhone* mi = new XiaoMi;
MobilePhone* hua = new HuaWei;
mi->appRun(gameApp);
mi->appRun(translateApp);
hua->appRun(gameApp);
hua->appRun(translateApp);
delete hua;
hua = nullptr;
delete mi;
mi = nullptr;
delete gameApp;
gameApp = nullptr;
delete translateApp;
translateApp = nullptr;
return 0;
}
11、裝飾模式(Decorator)
裝飾模式:動態地給一個對象添加一些額外的功能,它是通過創建一個包裝對象,也就是裝飾來包裹真實的對象。新增加功能來說,裝飾器模式比生產子類更加靈活。
以下情形考慮使用裝飾模式:
-
需要擴展一個類的功能,或給一個類添加附加職責。
-
需要動態的給一個對象添加功能,這些功能可以再動態的撤銷。
-
需要增加由一些基本功能的排列組合而產生的非常大量的功能,從而使繼承關系變的不現實。
-
當不能采用生成子類的方法進行擴充時。一種情況是,可能有大量獨立的擴展,為支持每一種組合將產生大量的子類,使得子類數目呈爆炸性增長。另一種情況可能是因為類定義被隱藏,或類定義不能用於生成子類。
/*
* 關鍵代碼:1、Component 類充當抽象角色,不應該具體實現。 2、修飾類引用和繼承 Component 類,具體擴展類重寫父類方法。
*/
#include <iostream>
using namespace std;
//抽象構件(Component)角色:給出一個抽象接口,以規范准備接收附加責任的對象。
class Component
{
public:
virtual ~Component(){}
virtual void configuration() = 0;
};
//具體構件(Concrete Component)角色:定義一個將要接收附加責任的類。
class Car : public Component
{
public:
void configuration() override
{
cout << "A Car" << endl;
}
};
//裝飾(Decorator)角色:持有一個構件(Component)對象的實例,並實現一個與抽象構件接口一致的接口。
class DecorateCar : public Component
{
public:
DecorateCar(Component* car) : m_pCar(car){}
void configuration() override
{
m_pCar->configuration();
}
private:
Component* m_pCar;
};
//具體裝飾(Concrete Decorator)角色:負責給構件對象添加上附加的責任。
class DecorateLED : public DecorateCar
{
public:
DecorateLED(Component* car) : DecorateCar(car){}
void configuration() override
{
DecorateCar::configuration();
addLED();
}
private:
void addLED()
{
cout << "Install LED" << endl;
}
};
//具體裝飾(Concrete Decorator)角色:負責給構件對象添加上附加的責任。
class DecoratePC : public DecorateCar
{
public:
DecoratePC(Component* car) : DecorateCar(car){}
void configuration() override
{
DecorateCar::configuration();
addPC();
}
private:
void addPC()
{
cout << "Install PC" << endl;
}
};
//具體裝飾(Concrete Decorator)角色:負責給構件對象添加上附加的責任。
class DecorateEPB : public DecorateCar
{
public:
DecorateEPB(Component* car) : DecorateCar(car){}
void configuration() override
{
DecorateCar::configuration();
addEPB();
}
private:
void addEPB()
{
cout << "Install Electrical Park Brake" << endl;
}
};
int main()
{
Car* car = new Car;
DecorateLED* ledCar = new DecorateLED(car);
DecoratePC* pcCar = new DecoratePC(ledCar);
DecorateEPB* epbCar = new DecorateEPB(pcCar);
epbCar->configuration();
delete epbCar;
epbCar = nullptr;
delete pcCar;
pcCar = nullptr;
delete ledCar;
ledCar = nullptr;
delete car;
car = nullptr;
return 0;
}
12、中介者模式(Mediator)
中介者模式:用一個中介對象來封裝一系列的對象交互,中介者使各對象不需要顯示地相互引用,從而使其耦合松散,而且可以獨立地改變它們之前的交互。
如果對象與對象之前存在大量的關聯關系,若一個對象改變,常常需要跟蹤與之關聯的對象,並做出相應的處理,這樣勢必會造成系統變得復雜,遇到這種情形可以考慮使用中介者模式。當多個對象存在關聯關系時,為它們設計一個中介對象,當一個對象改變時,只需要通知它的中介對象,再由它的中介對象通知每個與它相關的對象。
/*
* 關鍵代碼:將相關對象的通信封裝到一個類中單獨處理。
*/
#include <iostream>
using namespace std;
class Mediator;
//抽象同事類。
class Businessman
{
public:
Businessman(){}
Businessman(Mediator* mediator) : m_pMediator(mediator){}
virtual ~Businessman(){}
virtual void setMediator(Mediator* m)
{
m_pMediator = m;
}
virtual void sendMessage(const string& msg) = 0;
virtual void getMessage(const string& msg) = 0;
protected:
Mediator* m_pMediator;
};
//抽象中介者類。
class Mediator
{
public:
virtual ~Mediator(){}
virtual void setBuyer(Businessman* buyer) = 0;
virtual void setSeller(Businessman* seller) = 0;
virtual void send(const string& msg, Businessman* man) = 0;
};
//具體同事類
class Buyer : public Businessman
{
public:
Buyer() : Businessman(){}
Buyer(Mediator* mediator) : Businessman(mediator){}
void sendMessage(const string& msg) override
{
m_pMediator->send(msg, this);
}
void getMessage(const string& msg)
{
cout << "Buyer recv: " << msg.data() << endl;
}
};
//具體同事類
class Seller : public Businessman
{
public:
Seller() : Businessman(){}
Seller(Mediator* mediator) : Businessman(mediator){}
void sendMessage(const string& msg) override
{
m_pMediator->send(msg, this);
}
void getMessage(const string& msg)
{
cout << "Seller recv: " << msg.data() << endl;
}
};
//具體中介者類
class HouseMediator : public Mediator
{
public:
void setBuyer(Businessman* buyer) override
{
m_pBuyer = buyer;
}
void setSeller(Businessman* seller) override
{
m_pSeller = seller;
}
void send(const string& msg, Businessman* man) override
{
if(man == m_pBuyer)
{
m_pSeller->getMessage(msg);
}
else if(man == m_pSeller)
{
m_pBuyer->getMessage(msg);
}
}
private:
Businessman* m_pBuyer;
Businessman* m_pSeller;
};
int main()
{
HouseMediator* hMediator = new HouseMediator;
Buyer* buyer = new Buyer(hMediator);
Seller* seller = new Seller(hMediator);
hMediator->setBuyer(buyer);
hMediator->setSeller(seller);
buyer->sendMessage("Sell not to sell?");
seller->sendMessage("Of course selling!");
delete buyer;
buyer = nullptr;
delete seller;
seller = nullptr;
delete hMediator;
hMediator = nullptr;
return 0;
}
13、備忘錄模式(Memento)
備忘錄模式:在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象之外保存這個狀態。這樣以后就可以將該對象恢復到原來保存的狀態。
備忘錄模式中需要定義的角色類:
-
Originator(發起人):負責創建一個備忘錄Memento,用以記錄當前時刻自身的內部狀態,並可使用備忘錄恢復內部狀態。Originator可以根據需要決定Memento存儲自己的哪些內部狀態。
-
Memento(備忘錄):負責存儲Originator對象的內部狀態,並可以防止Originator以外的其他對象訪問備忘錄。備忘錄有兩個接口:Caretaker只能看到備忘錄的窄接口,他只能將備忘錄傳遞給其他對象。Originator卻可看到備忘錄的寬接口,允許它訪問返回到先前狀態所需要的所有數據。
-
Caretaker(管理者):負責備忘錄Memento,不能對Memento的內容進行訪問或者操作。
/*
* 關鍵代碼:Memento類、Originator類、Caretaker類;Originator類不與Memento類耦合,而是與Caretaker類耦合。
*/
include <iostream>
using namespace std;
//需要保存的信息
typedef struct
{
int grade;
string arm;
string corps;
}GameValue;
//Memento類
class Memento
{
public:
Memento(){}
Memento(GameValue value):m_gameValue(value){}
GameValue getValue()
{
return m_gameValue;
}
private:
GameValue m_gameValue;
};
//Originator類
class Game
{
public:
Game(GameValue value):m_gameValue(value)
{}
void addGrade() //等級增加
{
m_gameValue.grade++;
}
void replaceArm(string arm) //更換武器
{
m_gameValue.arm = arm;
}
void replaceCorps(string corps) //更換工會
{
m_gameValue.corps = corps;
}
Memento saveValue() //保存當前信息
{
Memento memento(m_gameValue);
return memento;
}
void load(Memento memento) //載入信息
{
m_gameValue = memento.getValue();
}
void showValue()
{
cout << "Grade: " << m_gameValue.grade << endl;
cout << "Arm : " << m_gameValue.arm.data() << endl;
cout << "Corps: " << m_gameValue.corps.data() << endl;
}
private:
GameValue m_gameValue;
};
//Caretaker類
class Caretake
{
public:
void save(Memento memento) //保存信息
{
m_memento = memento;
}
Memento load() //讀已保存的信息
{
return m_memento;
}
private:
Memento m_memento;
};
int main()
{
GameValue v1 = {0, "Ak", "3K"};
Game game(v1); //初始值
game.addGrade();
game.showValue();
cout << "----------" << endl;
Caretake care;
care.save(game.saveValue()); //保存當前值
game.addGrade(); //修改當前值
game.replaceArm("M16");
game.replaceCorps("123");
game.showValue();
cout << "----------" << endl;
game.load(care.load()); //恢復初始值
game.showValue();
return 0;
}
14、原型模式(Prototype)
原型模式:用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象。通俗的講就是當需要創建一個新的實例化對象時,我們剛好有一個實例化對象,但是已經存在的實例化對象又不能直接使用。這種情況下拷貝一個現有的實例化對象來用,可能會更方便。
以下情形可以考慮使用原型模式:
- 當new一個對象,非常繁瑣復雜時,可以使用原型模式來進行復制一個對象。比如創建對象時,構造函數的參數很多,而自己又不完全的知道每個參數的意義,就可以使用原型模式來創建一個新的對象,不必去理會創建的過程。
- 當需要new一個新的對象,這個對象和現有的對象區別不大,我們就可以直接復制一個已有的對象,然后稍加修改。
- 當需要一個對象副本時,比如需要提供對象的數據,同時又需要避免外部對數據對象進行修改,那就拷貝一個對象副本供外部使用。
/*
* 關鍵代碼:拷貝,return new className(*this);
*/
#include <iostream>
using namespace std;
//提供一個抽象克隆基類。
class Clone
{
public:
virtual Clone* clone() = 0;
virtual void show() = 0;
};
//具體的實現類
class Sheep:public Clone
{
public:
Sheep(int id, string name):Clone(),
m_id(id),m_name(name)
{
cout << "Sheep() id address:" << &m_id << endl;
cout << "Sheep() name address:" << &m_name << endl;
}
~Sheep()
{
}
//關鍵代碼拷貝構造函數
Sheep(const Sheep& obj)
{
this->m_id = obj.m_id;
this->m_name = obj.m_name;
cout << "Sheep(const Sheep& obj) id address:" << &m_id << endl;
cout << "Sheep(const Sheep& obj) name address:" << &m_name << endl;
}
//關鍵代碼克隆函數,返回return new Sheep(*this)
Clone* clone()
{
return new Sheep(*this);
}
void show()
{
cout << "id :" << m_id << endl;
cout << "name:" << m_name.data() << endl;
}
private:
int m_id;
string m_name;
};
int main()
{
Clone* s1 = new Sheep(1, "abs");
s1->show();
Clone* s2 = s1->clone();
s2->show();
delete s1;
s1 = nullptr;
delete s2;
s2 = nullptr;
return 0;
}
15、享元模式(Flyweight)
享元模式:運用共享技術有效地支持大量細粒度的對象。在有大量對象時,把其中共同的部分抽象出來,如果有相同的業務請求,直接返回內存中已有的對象,避免重新創建。
以下情況可以考慮使用享元模式:
- 系統中有大量的對象,這些對象消耗大量的內存,且這些對象的狀態可以被外部化。
對於享元模式,需要將對象的信息分為兩個部分:內部狀態和外部狀態。內部狀態是指被共享出來的信息,儲存在享元對象內部且不隨環境變化而改變;外部狀態是不可以共享的,它隨環境改變而改變,是由客戶端控制的。
/*
* 關鍵代碼:將內部狀態作為標識,進行共享。
*/
#include <iostream>
#include <map>
#include <memory>
using namespace std;
//抽象享元類,提供享元類外部接口。
class AbstractConsumer
{
public:
virtual ~AbstractConsumer(){}
virtual void setArticle(const string&) = 0;
virtual const string& article() = 0;
};
//具體的享元類
class Consumer : public AbstractConsumer
{
public:
Consumer(const string& strName) : m_user(strName){}
~Consumer()
{
cout << " ~Consumer()" << endl;
}
void setArticle(const string& info) override
{
m_article = info;
}
const string& article() override
{
return m_article;
}
private:
string m_user;
string m_article;
};
//享元工廠類
class Trusteeship
{
public:
~Trusteeship()
{
m_consumerMap.clear();
}
void hosting(const string& user, const string& article)
{
if(m_consumerMap.count(user))
{
cout << "A customer named " << user.data() << " already exists" << endl;
Consumer* consumer = m_consumerMap.at(user).get();
consumer->setArticle(article);
}
else
{
shared_ptr<Consumer> consumer(new Consumer(user));
consumer.get()->setArticle(article);
m_consumerMap.insert(pair<string, shared_ptr<Consumer>>(user, consumer));
}
}
void display()
{
map<string, shared_ptr<Consumer>>::iterator iter = m_consumerMap.begin();
for(; iter != m_consumerMap.end(); iter++)
{
cout << iter->first.data() << " : "<< iter->second.get()->article().data() << endl;
}
}
private:
map<string, shared_ptr<Consumer>> m_consumerMap;
};
int main()
{
Trusteeship* ts = new Trusteeship;
ts->hosting("zhangsan", "computer");
ts->hosting("lisi", "phone");
ts->hosting("wangwu", "watch");
ts->display();
ts->hosting("zhangsan", "TT");
ts->hosting("lisi", "TT");
ts->hosting("wangwu", "TT");
ts->display();
delete ts;
ts = nullptr;
return 0;
}
16、職責鏈模式(Chain of Resp.)
職責鏈模式:使多個對象都有機會處理請求,從而避免請求的發送者和接收者之前的耦合關系,將這些對象連成一條鏈,並沿着這條鏈傳遞請求,直到有一個對象處理它為止。
職責鏈上的處理者負責處理請求,客戶只需要將請求發送到職責鏈上即可,無需關心請求的處理細節和請求的傳遞,所有職責鏈將請求的發送者和請求的處理者解耦了。
/*
* 關鍵代碼:Handler內指明其上級,handleRequest()里判斷是否合適,不合適則傳遞給上級。
*/
#include <iostream>
using namespace std;
enum RequestLevel
{
Level_One = 0,
Level_Two,
Level_Three,
Level_Num
};
//抽象處理者(Handler)角色,提供職責鏈的統一接口。
class Leader
{
public:
Leader(Leader* leader):m_leader(leader){}
virtual ~Leader(){}
virtual void handleRequest(RequestLevel level) = 0;
protected:
Leader* m_leader;
};
//具體處理者(Concrete Handler)角色
class Monitor:public Leader //鏈扣1
{
public:
Monitor(Leader* leader):Leader(leader){}
void handleRequest(RequestLevel level)
{
if(level < Level_Two)
{
cout << "Mointor handle request : " << level << endl;
}
else
{
m_leader->handleRequest(level);
}
}
};
//具體處理者(Concrete Handler)角色
class Captain:public Leader //鏈扣2
{
public:
Captain(Leader* leader):Leader(leader){}
void handleRequest(RequestLevel level)
{
if(level < Level_Three)
{
cout << "Captain handle request : " << level << endl;
}
else
{
m_leader->handleRequest(level);
}
}
};
//具體處理者(Concrete Handler)角色
class General:public Leader //鏈扣3
{
public:
General(Leader* leader):Leader(leader){}
void handleRequest(RequestLevel level)
{
cout << "General handle request : " << level << endl;
}
};
int main()
{
Leader* general = new General(nullptr);
Leader* captain = new Captain(general);
Leader* monitor = new Monitor(captain);
monitor->handleRequest(Level_One);
delete monitor;
monitor = nullptr;
delete captain;
captain = nullptr;
delete general;
general = nullptr;
return 0;
}
