C++ 設計模式#
1 設計模式基礎#
1.1 設計模式基本原則#
最終目的: 高內聚,低耦合
(1)開放封閉原則(OCP, Open For Extension, Closed For Modification)
類的改動是通過增加代碼進行,而不是修改代碼。
(2)單一職責原則(SRP, Single Responsibility Principle)
類的職責要單一,對外只提供一種功能,而引起類變化的原因都應該只有一個。
(3)依賴倒置原則(DIP, Dependence Inversion Principle)
依賴於抽象(接口),不要依賴具體實現(類),也就是針對接口編程。
(4)接口隔離原則(ISP, Interface Segregation Principle)
不應該強迫客戶的程序依賴他們不需要的接口方法,一個接口應該只提供一種對外功能,不應該把所有操作封裝到一個接口中去。
(5)里氏替換原則(LSP, Liskov Substitution Principle)
任何抽象類出現的地方都可以用它的實現類進行替換,實際就是虛擬機制,語言級別實現面向對象功能。
(6)優先使用組合而不是繼承原則(CAPP, Composite/Aggregate Reuse Principle)
如果使用繼承,會導致父類的任何變化都可能影響到子類的行為。
如果使用對象組合,就降低了這種依賴。
(7)迪米特法則(LOD, Law Of Demeter)
一個對象應當對其它對象盡可能少的了解,從而降低各個對象之間的耦合,提高系統的可維護性。例如在一個程序中,各個模塊之間相互調用時,通常會提供一個統一的接口來實現。這樣其他模塊不需要了解另外一個模塊的內部實現細節,這樣當一個模塊內的實現發生改變時,不會影響其它模塊的使用。
2 依賴倒置和迪米特法則#
2.1 依賴倒置(DIP, Dependence Inversion Principle)#
在下面的程序裡,Computer 類並不依賴具體的類,而是依賴三個抽象類。通過對三個類的重寫,實現我們想要的功能。我們用重寫的子類初始化 Computer,減輕了依賴,增加了靈活性。
如圖所示:
代碼如下:
// 依賴倒置原則
// 依賴於抽象(接口),不要依賴具體實現(類),也就是針對接口編程。
#include <iostream>
using namespace std;
//抽象類HardDisk
class HardDisk{
public:
virtual void work() = 0;
};
//抽象類Memory
class Memory{
public:
virtual void work() = 0;
};
//抽象類Cpu
class Cpu{
public:
virtual void work() = 0;
};
//繼承HardDisk,並重寫work
class JSDhardDisk: public HardDisk{
public:
void work(){
cout << "JSDhardDisk is working" << endl;
}
};
//繼承Memory,並重寫work
class XSMemory: public Memory{
public:
void work(){
cout << "XSMemory is working" << endl;
}
};
//繼承Cpu,並重寫work
class InterCpu: public Cpu{
public:
void work(){
cout << "InterCpu is working" << endl;
}
};
//定義Computer類,使用的是組合的方式,而不是繼承
class Computer{
public:
//構造函數,初始化三個組合成員
Computer(HardDisk *hardDisk, Memory *memory, Cpu *cpu){
this->m_hardDisk = hardDisk;
this->m_memory = memory;
this->m_cpu = cpu;
}
//執行函數
void work(){
m_hardDisk->work();
m_memory->work();
m_cpu->work();
}
private:
//定義三個類,組合在Computer裡
HardDisk *m_hardDisk;
Memory *m_memory;
Cpu *m_cpu;
};
//測試函數
void test01(void){
//定義三個抽象類指針
HardDisk *hardDisk = NULL;
Memory *memory = NULL;
Cpu *cpu = NULL;
//用其子類的構造
hardDisk = new JSDhardDisk;
memory = new XSMemory;
cpu = new InterCpu;
Computer computer(hardDisk, memory, cpu);
computer.work();
delete cpu;
delete memory;
delete hardDisk;
}
//主函數
int main(void){
test01();
system("pause");
return 0;
}
2.2 迪米特法則(LOD, Law Of Demeter)#
方法一:
代碼如下:
#include <iostream>
using namespace std;
class Stranger{
public:
void speak(void){
cout << "I am Stranger" << endl;
}
};
class Friend{
public:
void speak(void){
cout << "I am your friend" << endl;
}
Stranger* get_Stranger(){
return new Stranger();
}
};
//Tom不直接訪問Stranger,而是通過Friend
class Tom{
public:
void speak(Friend &fri){
fri.speak();
Stranger *stranger = fri.get_Stranger();
stranger->speak();
}
};
void test01(void){
Tom tom;
Stranger stranger;
Friend fri;
tom.speak(fri);
}
int main(void){
test01();
system("pause");
return 0;
}
方法二:
#include <iostream>
using namespace std;
class Stranger{
public:
void play(void){
cout << "I am Stranger" << endl;
}
};
class Friend{
public:
void play(void){
cout << "I am your friend" << endl;
}
void playWithStranger(void){
Stranger *stranger = new Stranger;
stranger->play();
}
};
class Tom{
public:
void play(void){
cout << "I am Tom" << endl;
}
void setFriend(Friend *fri){
this->m_fri = fri;
}
void playWithFri(void){
m_fri->play();
}
void playWithStranger(void){
m_fri->playWithStranger();
}
private:
Friend *m_fri;
};
void test01(void){
Tom tom;
Friend *fri;
tom.setFriend(fri);
tom.playWithStranger();
delete fri;
}
int main(void){
test01();
system("pause");
return 0;
}
方法三:
Tom 依賴於 Stranger 的抽象,並不依賴具體的 Stranger。
#include <iostream>
using namespace std;
class Stranger{
public:
virtual void play(void) = 0;
};
class StrangerA: public Stranger{
public:
void play(void){
cout << "I am StrangerA" << endl;
}
};
class Friend{
public:
void play(void){
cout << "I am your friend" << endl;
}
};
class Tom{
public:
void setFriend(Friend *fri){
this->m_fri = fri;
}
void setStranger(Stranger *stranger){
this->m_stranger = stranger;
}
void play(void){
cout << "I am Tom" << endl;
m_fri->play();
m_stranger->play();
}
private:
Friend *m_fri;
Stranger *m_stranger;
};
void test01(void){
Tom tom;
Friend *fri = new Friend();
Stranger *stranger = new StrangerA();
tom.setFriend(fri);
tom.setStranger(stranger);
tom.play();
delete stranger;
delete fri;
}
int main(void){
test01();
system("pause");
return 0;
}
3 創建型模式#
3.1 單例模式#
3.1.1 懶漢模式和餓漢模式#
單例化通過將構造函數設置為私有,所以只能在類內部構造。類中設置了一個靜態變量,通過靜態函數對其進行初始化,從而保證一個類只能實例化一個對象。
懶漢模式在全局處初始化靜態對象,賦值其為 NULL。只有在調用其靜態函數時才進行構造,故稱其為懶漢模式。
懶漢模式代碼如下:
#include <iostream>
using namespace std;
class Singleton{
public:
static Singleton *getInstance(void){
if(m_singleton == NULL){
m_singleton = new Singleton();
}
return m_singleton;
}
static void freeInstance(void){
if(m_singleton != NULL){
delete m_singleton;
m_singleton = NULL;
}
}
private:
static Singleton* m_singleton;
Singleton(void){
cout << "The structure of Singleton" << endl;
}
};
Singleton* Singleton::m_singleton = NULL;
void test01(void){
Singleton *p1 = Singleton::getInstance();
Singleton *p2 = Singleton::getInstance();
if(p1 == p2){
cout << "p1 = p2" << endl;
}
else{
cout << "p1 != p2" << endl;
}
}
int main(void){
test01();
system("pause");
return 0;
}
餓漢模式在全局處初始化靜態對象。與懶漢模式的不同點在於:
static Singleton *getInstance(void){
return m_singleton;
}
Singleton* Singleton::m_singleton = new Singleton();
3.1.2 懶漢模式多線程#
懶漢模式由於他只會在調用其提供的接口才進行構造,並且一個類只能構造一個函數。在多線程下,當構造函數執行時間太長(超過單個線程分配的時間片),時間片結束後,後面的線程執行判斷需要構造的對象依然為 NULL,後面的線程會並發地對通一個對象進行構造。這樣一來,單個對象會被構造多次,便失去的單例的特性。
//懶漢模式在多線程下的問題
#include <iostream>
using namespace std;
#include <windows.h>
#include <process.h>
class Singleton{
public:
static Singleton *getInstance(void){
if(m_singleton == NULL){
count++;
m_singleton = new Singleton();
}
return m_singleton;
}
static void freeInstance(void){
if(m_singleton != NULL){
delete m_singleton;
m_singleton = NULL;
}
}
static void printS(void){
cout << "Singleton printS test\n";
}
private:
static Singleton* m_singleton;
static int count;
Singleton(void){
cout << "The structure of Singleton(begin)\n";
cout << "The structure of Singleton(end)\n";
Sleep(1000);
}
};
Singleton* Singleton::m_singleton = NULL;
int Singleton::count = 0;
void myThreadFunc(void*){
Singleton::getInstance()->printS();
}
void test01(void){
HANDLE hThread[10];
for(int i=0; i<3; i++){
hThread[i] = (HANDLE)_beginthread(myThreadFunc, 0, NULL);
}
for(int i=0; i<3; i++){
WaitForSingleObject(hThread[i],INFINITE);
}
Singleton::freeInstance();
}
int main(void){
test01();
system("pause");
return 0;
}
3.1.3 懶漢模式多線程同步優化#
懶漢模式在多線程下優化,通過的是設置臨界區,並且執行雙判斷。優化懶漢模式,保證一個類只能實例化一個對象。從而避免重複構造,使其符合單例的特性。
核心代碼如下:
CRITICAL_SECTION cs;
InitializeCriticalSection(&cs); //初始化臨界區
static Singleton *getInstance(void){
if(m_singleton == NULL){
EnterCriticalSection(&cs); //進入臨界區
if(m_singleton == NULL){
m_singleton = new Singleton();
}
LeaveCriticalSection(&cs); //離開臨界區
}
return m_singleton;
}
3.2 簡單工廠模式#
簡單工廠模式,不是標準設計模式,因為他不符合開閉原則,但是它簡單易用。
邏輯示意圖如下:
示例代碼在 Factor 裡的 public 方法構造對象,返回值是抽象類的指針,通過這個類的多態性,返回不同類型的指針,實現工廠化生產對象。代碼如下:
#include <iostream>
using namespace std;
#include <string.h>
//定義抽象類
class Fruit{
public:
virtual void getFruit(void) = 0;
};
//繼承抽象類,重寫getFruit
class Banana: public Fruit{
public:
void getFruit(void){
cout << "I am Banana" << endl;
}
};
//繼承抽象類,重寫getFruit
class Apple: public Fruit{
public:
void getFruit(void){
cout << "I am Apple" << endl;
}
};
//定義工廠,通過裡面的公共函數creat進行實例對象構造
class Factor{
public:
Fruit *creat(string p){
if(p == "Banana"){
return new Banana;
}
else if(p == "Apple"){
return new Apple;
}
else{
cout << "Not supported" << endl;
return NULL;
}
}
};
//測試函數
void test01(void){
Factor *fac = new Factor;
Fruit *fru = NULL;
fru = fac->creat("Banana");
fru->getFruit();
delete fru;
fru = fac->creat("Apple");
fru->getFruit();
delete fru;
delete fac;
}
int main(void){
test01();
system("pause");
return 0;
}
3.3 工廠模式#
本例中,工廠模式通過對兩個抽象類進行實現,分別是抽象水果類和抽象工廠類。先進行抽象工廠的實例化,生成實例化的工廠,在通過這個工廠生產指定水果。一個工廠生產一種水果,想要添加生產水果的類別時,則再加上一個水果類和一個該類的工廠,而不需要修改其它代碼,符合開閉原則,使得代碼可以靈活拓展。
思維圖如下:
示例代碼如下:
#include <iostream>
using namespace std;
//定義抽象類Fruit
class Fruit{
public:
virtual void sayName(void) = 0;
};
//繼承Fruit, 重寫sayName,定義Banana.
class Banana: public Fruit{
public:
void sayName(void){
cout << "I am Banana" << endl;
}
};
//繼承Fruit, 重寫sayName,定義Apple.
class Apple: public Fruit{
public:
void sayName(void){
cout << "I am Apple" << endl;
}
};
//定義抽象工廠AbFactor
class AbFactor{
public:
virtual Fruit *creat(void) = 0;
};
//繼承抽象工廠,重寫creat,定義BananaFactor
class BananaFactor: public AbFactor{
public:
Fruit *creat(void){
return new Banana;
}
};
//繼承抽象工廠,重寫creat,定義AppleFactor
class AppleFactor: public AbFactor{
public:
Fruit *creat(void){
return new Apple;
}
};
/////////////////////////////////////////////////////////////////
//使用工廠模式後添加新的類時,不用修改原來代碼,符合了開閉原則
class Pear: public Fruit{
public:
void sayName(void){
cout << "I am pear" << endl;
}
};
class PearFactor: public AbFactor{
Fruit *creat(void){
return new Pear;
}
};
//測試函數
void test01(void){
AbFactor *factor = NULL;
Fruit *fruit = NULL;
factor = new BananaFactor;
fruit = factor->creat();
fruit->sayName();
delete fruit;
delete factor;
factor = new AppleFactor;
fruit = factor->creat();
fruit->sayName();
delete fruit;
delete factor;
factor = new PearFactor;
fruit = factor->creat();
fruit->sayName();
delete fruit;
delete factor;
}
int main(void){
test01();
system("pause");
return 0;
}
3.4 抽象工廠#
工廠模式只能生產一個產品(要麼香蕉,要麼蘋果)抽象工廠可以一下生產一個產品族(裡面有很多產品組成)和工廠模式比起來,抽象工廠可以生產更多,但是可拓展性變差了。
示例代碼裡同時抽象了工廠和水果,以此分為南方工廠和北方工廠,兩個廠都生產 Apple 和 Banana,思路圖如下所示:
示例代碼如下:
#include <iostream>
using namespace std;
//抽象類Fruit
class Fruit{
public:
virtual void sayName(void) = 0;
};
//抽象工廠
class AbFactory{
public:
virtual Fruit *creatBanana(void) = 0;
virtual Fruit *creatApple(void) = 0;
};
class NorthBanana: public Fruit{
public:
void sayName(void){
cout << "I am Banana, I am from North" << endl;
}
};
class NorthApple: public Fruit{
public:
void sayName(void){
cout << "I am Apple, I am from North" << endl;
}
};
class SouthBanana: public Fruit{
public:
void sayName(void){
cout << "I am Banana, I am from south" << endl;
}
};
class SouthApple: public Fruit{
public:
void sayName(void){
cout << "I am Apple, I am from south" << endl;
}
};
class NorthFactor: public AbFactory{
public:
Fruit *creatBanana(void){
return new NorthBanana;
}
Fruit *creatApple(void){
return new NorthApple;
}
};
class SouthFactor: public AbFactory{
public:
Fruit *creatBanana(void){
return new SouthBanana;
}
Fruit *creatApple(void){
return new SouthApple;
}
};
//測試程序
void test01(void){
AbFactory *factor = NULL;
Fruit *fruit = NULL;
factor = new NorthFactor;
fruit = factor->creatApple();
fruit->sayName();
delete fruit;
fruit = factor->creatBanana();
fruit->sayName();
delete fruit;
delete factor;
factor = new SouthFactor();
fruit = factor->creatApple();
fruit->sayName();
delete fruit;
fruit = factor->creatBanana();
fruit->sayName();
delete fruit;
delete factor;
}
int main(void){
test01();
system("pause");
return 0;
}
3.5 建造者模式#
適用情況:一個對象構建比較複雜,將一個對象的構造和表示進行分離。
建造者模式,通過一個指揮者控制建造者進行建造,建造流程在指揮者手裡。建造者不用理會建造的具體情況,它只管建造所需的對象。
具體邏輯在於將建造者傳入指揮者,並且賦值給指揮者的私有屬性,在指揮者內部調用建造者的屬性對對象進行建造。建造後 Builder 的屬性已經改變,通過 getHouse () 獲取到 m_house,通過各類 get 方法,可以查詢到建築情況。
思路圖如下:
代碼如下:
#include <iostream>
using namespace std;
class House{
public:
void setDoor(string door){
this->m_door = door;
}
void setWall(string wall){
this->m_wall = wall;
}
void setWindow(string window){
this->m_window = window;
}
string getDoor(void){
cout << m_door << endl;
return m_door;
}
string getWall(void){
cout << m_wall << endl;
return m_wall;
}
string getWindow(void){
cout << m_window << endl;
return m_window;
}
private:
string m_door;
string m_wall;
string m_window;
};
//抽象建築
class Builder{
public:
virtual void buildWall(void) = 0;
virtual void buildDoor(void) = 0;
virtual void buildWindow(void) = 0;
virtual House *getHouse(void) = 0;
};
//具體建築Flat
class FlatBuilder: public Builder{
public:
FlatBuilder(void){
this->m_house = new House;
}
void buildWall(void){
m_house->setWall("Flat wall");
}
void buildDoor(void){
m_house->setDoor("Flat door");
}
void buildWindow(void){
m_house->setWindow("Flat window");
}
House *getHouse(void){
return this->m_house;
}
private:
House *m_house;
};
//具體建築Villa
class VillaBuilder: public Builder{
public:
VillaBuilder(void){
this->m_house = new House;
}
void buildWall(void){
m_house->setWall("Villa wall");
}
void buildDoor(void){
m_house->setDoor("Villa door");
}
void buildWindow(void){
m_house->setWindow("Villa window");
}
House *getHouse(void){
return m_house;
}
private:
House *m_house;
};
//設計者(指揮者),負責建造邏輯
//建造者,幹具體的活
class Director{
public:
Director(Builder *builder){
this->m_builder = builder;
}
void Construct(void){
m_builder->buildWall();
m_builder->buildWindow();
m_builder->buildDoor();
}
private:
Builder *m_builder;
};
//測試程序
void test01(void){
House *house = NULL;
Builder *builder = NULL;
Director *director = NULL;
builder = new VillaBuilder;
director = new Director(builder);
director->Construct();
house = builder->getHouse();
house->getDoor();
house->getWall();
house->getWindow();
delete house;
delete builder;
delete director;
builder = new FlatBuilder;
director = new Director(builder);
director->Construct();
house = builder->getHouse();
house->getDoor();
house->getWall();
house->getWindow();
delete house;
delete builder;
delete director;
}
int main(void){
test01();
system("pause");
return 0;
}
3.6 原型模式#
原型模式原理:一個複雜對象,具有自我複製作用(有時候要注意深淺拷貝),統一一套接口。
示例思路圖如下:
示例代碼如下:
// 此處演示的是原型模式
#include <iostream>
using namespace std;
#include <string.h>
class Person{
public:
virtual Person *clone(void) = 0;
virtual void printT(void) = 0;
};
class CppProgrammer: public Person{
public:
CppProgrammer(void){
this->m_name = "";
this->m_age = 0;
}
CppProgrammer(string name, int age){
this->m_name = name;
this->m_age = age;
}
virtual void printT(void){
cout << "name: " << m_name << " age: " << m_age << endl;
}
virtual Person *clone(void){
CppProgrammer *tmp = new CppProgrammer;
*tmp = *this;
return tmp;
}
private:
string m_name;
int m_age;
};
void test01(void){
Person *p1 = new CppProgrammer("Tom",18);
p1->printT();
Person *p2 = p1->clone();
p2->printT();
}
int main(void){
test01();
system("pause");
return 0;
}
4 結構型模式#
結構模式的意義在於讓類和類進行組合,獲得更大的結構。
4.1 代理模式#
代理模式又叫委託模式,是為某個對象提供代理對象,並且由代理控制對原對象的訪問。代理通俗地講就是我們生活中的中介。
示例思路圖如下:
示例代碼裡創建了一個抽象類 Subject,被 RealSubjectBook 和 DangdangProxy 繼承了。代理 DangdangProxy 重寫了 sailbook 這個方法,並且通過組合的形式獲得了一個 RealSubjectBook 對象。我們可以在 DangdangProxy 繼承的 sailbook 方法裡調用 RealSubjectBook 重寫的方法,並且可以添加新的方法,這樣就實現了代理。
示例代碼如下:
#include <iostream>
using namespace std;
class Subject{
public:
virtual void sailbook(void) = 0;
};
class RealSubjectBook: public Subject{
public:
virtual void sailbook(void){
cout << "sail book" << endl;
}
};
class DangdangProxy: public Subject{
public:
DangdangProxy(void){
m_subject = new RealSubjectBook;
}
virtual void sailbook(void){
dazhe();
m_subject->sailbook();
dazhe();
}
void dazhe(void){
cout << "11.11 discount" << endl;
}
private:
Subject *m_subject;
};
void test01(void){
Subject *s = NULL;
s = new DangdangProxy;
s->sailbook();
delete s;
}
int main(void){
test01();
system("pause");
return 0;
}
4.2 裝飾模式#
裝飾模式又叫包裝模式。通過一種對客戶端透明的方式來擴展對象的功能,是繼承關係的一個替代方案。
裝飾模式就是把要添加的附加功能分別放在單獨的類中,並讓這些類包含它所要修飾的對象,當需要執行時,客戶端有選擇地,按順序地使用裝飾功能包裝對象。
邏輯示例圖如下:
示例代碼中的 RunCar,SwimCarDecorator,FlyCarDecorator 都繼承了基類 Car。不同於 RunCar 的單純重寫 show () 函數,兩個 Decorator 把構造函數設置為有參構造,初始化時需要傳入被裝飾的對象,並且重寫的 show 函數,會先調用被修飾的屬性的 show 函數。通過層層修飾,可以不斷擴充功能。
示例代碼如下:
#include <iostream>
using namespace std;
class Car{
public:
virtual void show(void) = 0;
};
class RunCar: public Car{
public:
virtual void show(void){
cout << "I can run" << endl;
}
};
class FlyCarDecorator: public Car{
public:
FlyCarDecorator(Car *car){
m_car = car;
}
void show(void){
m_car->show();
cout << "I can fly" << endl;
}
private:
Car *m_car;
};
class SwimCarDecorator: public Car{
public:
SwimCarDecorator(Car *car){
m_car = car;
}
void show(void){
m_car->show();
cout << "I can swim" << endl;
}
private:
Car *m_car;
};
void test01(void){
RunCar *runcar = NULL;
SwimCarDecorator *smCarDec = NULL;
FlyCarDecorator *flyCarDec = NULL;
cout << "RunCar:" << endl;
runcar = new RunCar;
runcar->show();
cout << endl;
cout << "Add Swim function:" << endl;
smCarDec = new SwimCarDecorator(runcar);
smCarDec->show();
cout << endl;
cout << "Add fly function:" << endl;
flyCarDec = new FlyCarDecorator(smCarDec);
flyCarDec->show();
}
int main(void){
test01();
system("pause");
return 0;
}
4.3 適配器模式#
適配器可以改變已有類的接口,適用於將類的接口轉化為客戶端希望的另外一個接口,使得原本由於接口不兼容而導致不能一起工作的那些類可以一起工作。
適配器模式邏輯圖如下:
代碼裡客戶端的需求是需要 220v,我們通過繼承抽象類 Current18v,並重寫 useCurrent18v,在 useCurrent18v 裡我們將從構造函數裡初始化的私有屬性進行方法調用。於是 useCurrent18v 便打印了”I am 220v, welcome“。
代碼如下:
#include <iostream>
using namespace std;
class Current18v{
public:
virtual void useCurrent18v(void) = 0;
};
class Current220v{
public:
virtual void useCurrent220v(void){
cout << "I am 220v, welcome" << endl;
}
};
class Adapter: public Current18v{
public:
Adapter(Current220v *current){
m_current = current;
}
virtual void useCurrent18v(void){
cout << "adapt for Current220v" << endl;
m_current->useCurrent220v();
}
private:
Current220v *m_current;
};
void test01(void){
Current18v *c18v = NULL;
Current220v *c220v = NULL;
Adapter *adapter = NULL;
c220v = new Current220v;
adapter = new Adapter(c220v);
adapter->useCurrent18v();
}
int main(void){
test01();
system("pause");
return 0;
}
4.4 組合模式#
組合模式(Composite Pattern),又叫部分整體模式,是 GoF 的 23 種設計模式中的一種構造型設計模式。 組合模式 是用於把一組相似的對象當作一個單一的對象。組合模式依據樹形結構來組合對象,用來表示部分以及整體層次。它創建了對象組的樹形結構。
示例圖如下:
示例代碼通過文件的性質分為文件夾文件和普通文件,通過將指針(包含文件指針和文件夾指針)放入 list 中並在 list 中嵌套 list,以此實現樹狀結構。showTree () 函數通過遞歸,打印出了文件列表。代碼如下:
#include <iostream>
using namespace std;
#include <list>
#include <string>
class IFile{
public:
virtual void display(void) = 0;
virtual int add(IFile *ifile) = 0;
virtual int remove(IFile *ifile) = 0;
virtual list<IFile*> *getChild(void) = 0;
};
class File: public IFile{
public:
File(string name){
m_name = name;
}
virtual void display(void){
cout << m_name << endl;
}
virtual int add(IFile *ifile){
return -1;
}
virtual int remove(IFile *ifile){
return -1;
}
virtual list<IFile*> *getChild(void){
return NULL;
}
private:
string m_name;
};
class Dir: public IFile{
public:
Dir(string name){
m_name = name;
m_list = new list<IFile*>;
m_list->clear();
}
virtual void display(void){
cout << m_name << endl;
}
virtual int add(IFile *ifile){
m_list->push_back(ifile);
return 0;
}
virtual int remove(IFile *ifile){
m_list->remove(ifile);
return 0;
}
virtual list<IFile*> *getChild(void){
return m_list;
}
private:
string m_name;
list<IFile *> *m_list;
};
//遞歸地顯示樹
void showTree(IFile *root, int num=0){
//顯示根節點
//若根節點有孩子
//如果孩子是文件,顯示名字
//若孩子是目錄,顯示目錄名字,showTree(子目錄)
if(root == NULL){
return;
}
for(int i=0; i<num; i++){
printf("\t");
}
//顯示根節點
root->display();
list<IFile*> *mylist = root->getChild();
if(mylist != NULL){ //說明是一個目錄
for(list<IFile*>::iterator it = mylist->begin(); it!=mylist->end(); it++){
if((*it)->getChild() == NULL){
for(int i=0; i<=num; i++){
printf("\t");
}
(*it)->display();
}
else{
showTree(*it,num+1);
}
}
}
}
void test01(void){
Dir *root = new Dir("C");
Dir *dir = new Dir("aaa.text");
File *file = new File("111.dir");
root->add(dir);
root->add(file);
list<IFile*> *f_list = root->getChild();
for(list<IFile*>::iterator it = f_list->begin(); it!=f_list->end(); it++){
(*it)->display();
}
cout << "\nAll file under root:" << endl;
Dir *dir2 = new Dir("222.dir");
File *file2 = new File("bbb.text");
Dir *dir3 = new Dir("333.dir");
File *file3 = new File("ccc.text");
dir->add(dir2);
dir->add(file2);
dir2->add(dir3);
dir2->add(file3);
showTree(root);
}
int main(void){
test01();
system("pause");
return 0;
}
4.5 橋接模式#
橋接(Bridge)是用於把抽象化與實現化解耦,使得二者可以獨立變化。這種類型的設計模式屬於結構型模式,它通過提供抽象化和實現化之間的橋接結構,來實現二者的解耦。
這種模式涉及到一個作為橋接的接口,使得實體類的功能獨立於接口實現類。這兩種類型的類可被結構化改變而互不影響。
思路示例圖如下:
示例代碼中抽象了 Engine 和 Car,讓 Car 類中持有 Engine 的指針,於是 Car 則符合了面向接口編程。在這種情況下,Car 的子類和 Engine 的子類可以單獨變化而對對象沒有影響。
如下:
#include <iostream>
using namespace std;
//抽象類Engine
class Engine{
public:
virtual void installEngine(void) = 0;
};
class Engine4400c: public Engine{
public:
virtual void installEngine(void){
cout << "I am Engine4400c, install completed" << endl;
}
};
class Engine4500c: public Engine{
public:
virtual void installEngine(void){
cout << "I am Engine4500c, install completed" << endl;
}
};
class Car{
public:
Car(Engine *engine){
m_engine = engine;
}
virtual void installEngine(void) = 0;
protected:
Engine *m_engine;
};
class BMW5: public Car{
public:
BMW5(Engine *engine): Car(engine){
}
virtual void installEngine(void){
m_engine->installEngine();
}
};
class BMW7: public Car{
public:
BMW7(Engine *engine): Car(engine){
}
virtual void installEngine(void){
m_engine->installEngine();
}
};
void test01(void){
Engine *engine = NULL;
BMW7 *bmw7 = NULL;
engine = new Engine4500c;
bmw7 = new BMW7(engine);
bmw7->installEngine();
}
int main(void){
test01();
system("pause");
return 0;
}
4.6 外觀模式#
外觀(Facade)模式又叫作門面模式,是一種通過為多個複雜的子系統提供一個一致的接口,而使這些子系統更加容易被訪問的模式。該模式對外有一個統一接口,外部應用程序不用關心內部子系統的具體細節,這樣會大大降低應用程序的複雜度,提高了程序的可維護性。
思路圖如下:
示例中,把原來執行時需要的各個流程封裝到了一个類中,這時我們再調用時就不需要執行繁雜的操作,而是直接用 Facade 這個類操作我們需要的流程。代碼如下:
#include <iostream>
using namespace std;
class SubSystemA{
public:
void doThing(void){
cout << "SubSystemA run" << endl;
}
};
class SubSystemB{
public:
void doThing(void){
cout << "SubSystemB run" << endl;
}
};
class SubSystemC{
public:
void doThing(void){
cout << "SubSystemC run" << endl;
}
};
class Facade{
public:
Facade(void){
sysa = new SubSystemA;
sysb = new SubSystemB;
sysc = new SubSystemC;
}
~Facade(void){
delete sysa;
delete sysb;
delete sysc;
}
void doThing(void){
sysa->doThing();
sysb->doThing();
sysc->doThing();
}
private:
SubSystemA *sysa;
SubSystemB *sysb;
SubSystemC *sysc;
};
void test01(void){
Facade *facade = new Facade;
facade->doThing();
delete facade;
}
int main(void){
test01();
system("pause");
return 0;
}
4.7 享元模式#
1) 享元模式(Flyweight Pattern) 也叫 蝇量模式:運用共享技術有效地支持大量細粒度的對象。
2) 常用於系統底層開發,解決系統的性能問題。像數據庫連接池,裡面都是創建好的連接對象,在這些連接對象中有我們需要的則直接拿來用,避免重新創建,如果沒有我們需要的,則創建一個。
3) 享元模式能夠解決重複對象的內存浪費的問題,當系統中有大量相似對象,需要緩衝池時。不需總是創建新對象,可以從緩衝池裡拿。這樣可以降低系統內存,同時提高效率。
邏輯思路圖如下:
示例代碼中有個 FlyWeightFactor 的類,它內部有一個 getTeacher 方法,我們通過它創建對象,如果我們已經有這個序號對應的對象則不需要創建,直接從 map 裡取出,如果沒有,我們需要 new 一個新的對象。通過這種模式,我們解決了對象內存浪費問題,提高了效率。
#include <iostream>
using namespace std;
#include <map>
class Person{
public:
Person(string name, int age){
m_name = name;
m_age = age;
}
virtual void printT(void) = 0;
protected:
string m_name;
int m_age;
};
class Teacher: public Person{
public:
Teacher(string name, int age, string id): Person(name, age){
m_id = id;
}
void printT(void){
cout << "name: " << m_name << " age: " << m_age << " id: " << m_id << endl;
}
private:
string m_id;
};
class FlyWeightFactor{
public:
FlyWeightFactor(void){
m_map1.clear();
}
~FlyWeightFactor(void){
for(map<string,Person*>::iterator it = m_map1.begin(); it != m_map1.end(); it++){
delete (it->second);
}
}
Person *getTeacher(string id){
map<string, Person*>::iterator it;
it = m_map1.find(id);
Person *tmp = NULL;
if(it == m_map1.end()){
string name;
int age;
cout << "Please input the name of teacher" << endl;
cin >> name;
cout << "Please input the age of the teacher" << endl;
cin >> age;
tmp = new Teacher(name, age, id);
m_map1.insert(pair<string, Person*>(id, tmp));
}
else{
tmp = it->second;
}
return tmp;
}
private:
map<string, Person*> m_map1;
};
void test01(void){
FlyWeightFactor *fwf = NULL;
Person *p1 = NULL;
Person *p2 = NULL;
Person *p3 = NULL;
fwf = new FlyWeightFactor;
p1 = fwf->getTeacher("10");
p1->printT();
p2 = fwf->getTeacher("9");
p2->printT();
p3 = fwf->getTeacher("9");
p2->printT();
}
int main(void){
test01();
system("pause");
return 0;
}
5 行為型模式#
5.1 模板模式#
模板方法把具有特定步驟算法中的某些必要的處理委讓給抽象方法。通過子類繼承對抽象方法的不同實現改變整個算法的行為。
總結:
在抽象類中統一操作步驟,並規定好接口;讓子類實現接口。這樣可以把各個具體子類和操作步驟接耦合。
邏輯思路圖如下:
示例代碼裡,我們在 Base 這個基類裡有一個 run 方法,這裡規定了方法的具體運行流程。我們繼承 Base,得到 Son 這個類在 Son 裡對其中的方法進行重寫,達到多態的效果。代碼如下:
//本程序實現的是模板方法
#include <iostream>
using namespace std;
class Base{
public:
void run(void){
step1();
if(step2()){
step3();
}
for(int i=0; i<4; i++){
step4();
}
step5();
}
virtual ~Base(void){ };
protected:
void step1(void){
cout << "step1 call" << endl;
}
void step3(void){
cout << "step3 call" << endl;
}
void step5(void){
cout << "step5 call" << endl;
}
virtual bool step2(void) = 0;
virtual void step4(void) = 0;
int *p;
};
class Son:public Base{
protected:
virtual bool step2(void){
return 1;
}
virtual void step4(void){
cout << "step4 call" << endl;
}
};
int main(void){
Base *p = new Son();
p->run();
delete p;
system("pause");
return 0;
}
5.2 命令模式#
命令模式是一個高內聚的模式,其定義為:將一個請求封裝成一個對象,從而讓你使用不同的請求把客戶端參數化,對請求排隊或者記錄請求日誌,可以提供命令的撤銷和恢復功能。
邏輯思路圖如下:
#include <iostream>
using namespace std;
#include <string>
#include <list>
class Doctor{
public:
void treat_eyes(void){
cout << "treat eyes" << endl;
}
void treat_nose(void){
cout << "treat nose" << endl;
}
};
class Command{
public:
virtual void treat(void) = 0;
};
class CommandTreatEyes: public Command{
public:
CommandTreatEyes(Doctor *doctor){
m_doctor = doctor;
}
virtual void treat(void){
m_doctor->treat_eyes();
}
private:
Doctor *m_doctor;
};
class CommandTreatNose: public Command{
public:
CommandTreatNose(Doctor *doctor){
m_doctor = doctor;
}
void treat(void){
m_doctor->treat_nose();
}
private:
Doctor *m_doctor;
};
class Nurse{
public:
Nurse(Command *command){
m_command = command;
}
void submittedCase(void){
m_command->treat();
}
private:
Command *m_command;
};
class HeadNurse{
public:
HeadNurse(){
m_list.clear();
}
void setCommand(Command *command){
m_list.push_back(command);
}
void SubmittedCommand(void){
for(list<Command*>::iterator it = m_list.begin(); it!=m_list.end(); it++){
(*it)->treat();
}
}
private:
list<Command*> m_list;
};
void test01(void){
Doctor *doctor = NULL;
Command *command = NULL;
Nurse *nurse = NULL;
doctor = new Doctor;
command = new CommandTreatEyes(doctor);
nurse = new Nurse(command);
nurse->submittedCase();
}
void test02(void){
Doctor *doctor = NULL;
Command *command1 = NULL;
Command *command2 = NULL;
Command *command3 = NULL;
HeadNurse *hnurse = NULL;
doctor = new Doctor;
command1 = new CommandTreatEyes(doctor);
command2 = new CommandTreatNose(doctor);
command3 = new CommandTreatEyes(doctor);
hnurse = new HeadNurse;
hnurse->setCommand(command1);
hnurse->setCommand(command2);
hnurse->setCommand(command3);
hnurse->SubmittedCommand();
}
int main(void){
// test01();
test02();
system("pause");
return 0;
}
5.3 責任鏈模式#
為了避免請求發送者與多個請求處理者耦合在一起,將所有請求的處理者通過前一對象記住其下一個對象的引用而連成一條鏈;當有請求發生時,可將請求沿著這條鏈傳遞,直到有對象處理它為止。
邏輯思路圖如下:
示例代碼裡,我們抽象了一個類 CarHandle,三個類繼承了 CarHandle 並對其方法 handleCar 和 setNextHandle 進行了繼承重寫。重要的是通過 setNextHandle 函數賦值給其保護屬性 m_carhandle,並在 handleCar 裡自動調用其 handleCar 方法。這個方法下我們可以設置責任鏈的傳播次序,使用頭部的 handleCar 便可以鏈式地訪問所有 handleCar 函數。代碼如下:
#include <iostream>
using namespace std;
class CarHandle{
public:
virtual void handleCar(void) = 0;
virtual void setNextHandle(CarHandle *carhandle) = 0;
protected:
CarHandle *m_carhandle;
};
class HeadCarHandle: public CarHandle{
public:
virtual void handleCar(void){
cout << "Handle the head of the car" << endl;
if(m_carhandle != NULL){
m_carhandle->handleCar();
}
}
virtual void setNextHandle(CarHandle *carhandle){
m_carhandle = carhandle;
}
};
class BodyCarHandle: public CarHandle{
public:
virtual void handleCar(void){
cout << "Handle the body of the car" << endl;
if(m_carhandle != NULL){
m_carhandle->handleCar();
}
}
virtual void setNextHandle(CarHandle *carhandle){
m_carhandle = carhandle;
}
};
class TailCarHandle: public CarHandle{
public:
virtual void handleCar(void){
cout << "Handle the tail of the car" << endl;
if(m_carhandle != NULL){
m_carhandle->handleCar();
}
}
virtual void setNextHandle(CarHandle *carhandle){
m_carhandle = carhandle;
}
};
void test01(void){
CarHandle *head = new HeadCarHandle;
CarHandle *body = new BodyCarHandle;
CarHandle *tail = new TailCarHandle;
head->setNextHandle(body);
body->setNextHandle(tail);
tail->setNextHandle(NULL);
head->handleCar();
delete head;
delete body;
delete tail;
}
int main(void){
test01();
system("pause");
return 0;
}
5.4 策略模式#
策略模式是一種簡單卻常用的設計模式,它的應用場景非常廣泛。該模式定義了一系列算法,並將每個算法封裝起來,使它們可以相互替換,且算法的變化不會影響使用算法的客戶。策略模式屬於對象行為模式,它通過對算法進行封裝,把使用算法的責任和算法的實現分割開來,並委派給不同的對象對這些算法進行管理。
該模式主要解決在有多種算法相似的情況下,使用 if...else
所帶來的複雜和難以維護。它的優點是算法可以自由切換,同時可以避免多重if...else
判斷,且具有良好的擴展性。
代碼邏輯圖如下:
示例代碼裡抽象了一个 TaxSterategy 接口,SalesOrder 地實現依賴於它,下面若干類繼承 TaxSterategy 並對其方法進行重寫。SalesOrder 採用 TaxSterategy 的子類初始化對象,通過對象的多態性實現不同的效果。如果想擴展程序,只需要繼承重寫基類就行了,相對於用傳統的分支 if...else...,在代碼的維護上有優勢,並且符合開放封閉原則。代碼如下:
//此處實驗的是策略方法
//策略方法對比於傳統的多分支實現法,具有可擴展,易維護的特性
#include <iostream>
using namespace std;
//抽象Tax類型
class TaxSterategy{
public:
virtual double calculate() = 0;
virtual ~TaxSterategy(){ };
};
//具體分類(CN_Tax類),對抽象Tax繼承
class CN_Tax:public TaxSterategy{
public:
virtual double calculate(){
cout << "CN_Tax" << endl;
return 1;
}
};
//具體分類(US_Tax類),對抽象Tax繼承
class US_Tax:public TaxSterategy{
public:
virtual double calculate(){
cout << "US_Tax" << endl;
return 2;
}
};
//具體分類(DE_Tax類),對抽象Tax繼承
class DE_Tax:public TaxSterategy{
public:
virtual double calculate(){
cout << "DE_Tax" << endl;
return 3;
}
};
//具體分類(FR_Tax類),對抽象Tax繼承
class FR_Tax:public TaxSterategy{
public:
virtual double calculate(){
cout << "FR_Tax" << endl;
return 4;
}
};
//定義操作他們的類
class SalesOrder{
private:
TaxSterategy *tax;
public:
//有參構造函數
SalesOrder(TaxSterategy *country){
this->tax = country;
}
//析構函數,刪除tax指針
~SalesOrder(){
delete tax;
}
double CalculateTax(){
return this->tax->calculate();
}
};
//測試程序
void test01(void){
FR_Tax *fr = new FR_Tax();
SalesOrder order(fr);
cout << order.CalculateTax() << endl;
}
//主函數
int main(void){
test01();
system("pause");
return 0;
}
5.5 中介者模式#
中介者模式(Mediator Pattern)定義:用一個中介對象來封裝一系列的對象交互,中介者使各對象不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的交互。中介者模式又稱為調停者模式,它是一種對象行為型模式。
邏輯思路圖如下:
示例代碼裡,我們通過一個中介者 Mediator 抽象,將其指針傳入各類,這是我們不再通過自身連接不同 Person 對象,而是通過 Mediator 的子類對象對兩個 Person 對象作用。通過不同的 Mediator 子類對象,我們可以對連接對象進行不同操作,示例代碼裡舉例了找對象的邏輯。代碼如下:
#include <iostream>
using namespace std;
#include <string>
class Mediator;
class Person{
public:
Person(string name, int sex, int condi, Mediator *m){
m_name = name;
m_sex = sex;
m_condi = condi;
m_mediator = m;
}
int getCondi(void){
return m_condi;
}
int getSex(void){
return m_sex;
}
string getName(void){
return m_name;
}
virtual void getParter(Person *person) = 0;
protected:
string m_name;
int m_sex;
int m_condi;
Mediator *m_mediator;
};
class Mediator{
public:
virtual void setMen(Person *men) = 0;
virtual void setWomen(Person *women) = 0;
virtual void getParter(void) = 0;
protected:
Person *pmen;
Person *pwomen;
};
class Mediator_a: public Mediator{
public:
virtual void setMen(Person *men){
pmen = men;
}
virtual void setWomen(Person *women){
pwomen = women;
}
virtual void getParter(void){
if(pmen->getSex() == pwomen->getSex()){
cout << "I am not gay" << endl;
}
else if(pmen->getCondi() == pwomen->getCondi()){
cout << pmen->getName() << " and " << pwomen->getName() << " are a perfect match" << endl;
}
else{
cout << pmen->getName() << " and " << pwomen->getName() << " are not a match" << endl;
}
}
};
class Men: public Person{
public:
Men(string name, int sex, int condi, Mediator *m): Person(name, sex, condi, m){
}
virtual void getParter(Person *person){
m_mediator->setMen(this);
m_mediator->setWomen(person);
m_mediator->getParter();
}
};
class Women: public Person{
public:
Women(string name, int sex, int condi, Mediator *m): Person(name, sex, condi, m){
}
virtual void getParter(Person *person){
m_mediator->setMen(person);
m_mediator->setWomen(this);
m_mediator->getParter();
}
};
// //直接找對象
// void test01(void){
// Person *p1 = new Women("lucy", 0, 2);
// Person *p2 = new Men("jack", 1, 4);
// Person *p3 = new Men("Mark", 1, 2);
// p1->getParter(p2);
// p1->getParter(p3);
// }
//通過中介找對象
void test02(void){
Mediator *m = new Mediator_a;
Person *p1 = new Women("lucy", 0, 2, m);
Person *p2 = new Men("jack", 1, 4, m);
Person *p3 = new Men("Mark", 1, 2, m);
p1->getParter(p2);
p1->getParter(p3);
p2->getParter(p3);
}
int main(void){
// test01();
test02();
system("pause");
return 0;
}
5.6 觀察者模式#
觀察者模式,屬於行為型模式的一種,它定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態變化時,會通知所有的觀察者對象,使他們能夠自動更新自己。
邏輯思路圖如下:
示例代碼裡通過 Boss 裡的一個 list 收集 hero 對象,hero 作為觀察對象,當 boss 裡刪除 hero 時,通過 boss 裡的 notify 函數從迭代器裡取出 hero 對象,並對其進行告知。此處只展示模型,通過修改可實現告知哪個 hero 被刪除。代碼如下:
//此處實驗的是觀察者模式
#include <iostream>
#include <windows.h>
#include <string>
#include <list>
using namespace std;
//抽象英雄類
class AbstractHero{
public:
virtual void update(void) = 0;
};
//繼承抽象英雄類,定義Hero1
class Hero1: public AbstractHero{
public:
Hero1(){
cout << "Hero1 is call" << endl;
}
virtual void update(void){
cout << "Hero1 is stop" << endl;
}
};
//繼承AbstractHero,定義Hero2
class Hero2: public AbstractHero{
public:
Hero2(){
cout << "Hero2 is call" << endl;
}
virtual void update(){
cout << "Hero2 is stop" << endl;
}
};
//繼承抽象英雄類,定義Hero3
class Hero3: public AbstractHero{
public:
Hero3(){
cout << "Hero3 is call" << endl;
}
virtual void update(){
cout << "Hero3 is stop" << endl;
}
};
//抽象Boss類
class AbstractBoss{
public:
//添加觀察者
virtual void addHero(AbstractHero *hero) = 0;
//刪除觀察者
virtual void deleteHero(AbstractHero *hero) = 0;
//通知函數
virtual void notify(void) = 0;
};
//繼承AbstractBoss,定義Boss1
class Boss1: public AbstractBoss{
public:
Boss1(void){
this->list_hero.clear();
}
virtual void addHero(AbstractHero *hero){
list_hero.push_back(hero);
}
virtual void deleteHero(AbstractHero *hero){
list_hero.remove(hero);
}
virtual void notify(void){
for(list<AbstractHero*>::iterator it = list_hero.begin(); it!=list_hero.end(); it++){
(*it)->update();
}
}
private:
list<AbstractHero*> list_hero;
};
void test01(void){
AbstractHero *hero1 = new Hero1;
AbstractHero *hero2 = new Hero2;
AbstractHero *hero3 = new Hero3;
AbstractBoss *bos = new Boss1;
bos->addHero(hero1);
bos->addHero(hero2);
bos->addHero(hero3);
cout << "1**********" << endl;
bos->notify();
bos->deleteHero(hero3);
cout << "2**********" << endl;
bos->notify();
delete hero1;
delete hero2;
delete hero3;
delete bos;
}
int main(void){
test01();
system("pause");
return 0;
}
5.7 備忘錄模式#
備忘錄模式,是行為模式之一。它的作用是保護對象的內部狀態,並在需要的時候恢復對象以前的狀態。
邏輯思路圖如下:
對象 Person 通過持有一個 MemoTo 的指針,對其數據進行拷貝操作,有需要時進行恢復。CareTaker 類也可以對 Person 數據進行拷貝,好處是,通過它可以不持有 Person 指針進行恢復工作。代碼如下:
#include <iostream>
using namespace std;
#include <string>
class MemoTo{
public:
MemoTo(string name, int age){
m_name = name;
m_age = age;
}
void setName(string name){
m_name = name;
}
void setAge(int age){
m_age = age;
}
string getName(void){
return m_name;
}
int getAge(void){
return m_age;
}
private:
string m_name;
int m_age;
};
class Person{
public:
Person(string name, int age){
m_name = name;
m_age = age;
}
void setName(string name){
m_name = name;
}
void setAge(int age){
m_age = age;
}
string getName(void){
return m_name;
}
int getAge(void){
return m_age;
}
MemoTo *creatMeno(void){
m_meno = new MemoTo(m_name, m_age);
return m_meno;
}
void recover(void){
m_name = m_meno->getName();
m_age = m_meno->getAge();
}
void recover(MemoTo *memo){
m_name = memo->getName();
m_age = memo->getAge();
}
void printD(void){
cout << "name: " << m_name << " age: " << m_age << endl;
}
private:
string m_name;
int m_age;
MemoTo *m_meno;
};
class CareTaker{
public:
CareTaker(MemoTo *memo){
m_memo = memo;
}
void setMemo(MemoTo *memo){
m_memo = memo;
}
MemoTo *recover(void){
return m_memo;
}
private:
MemoTo *m_memo;
};
// void test01(void){
// Person *p1 = new Person("Tom", 18);
// p1->creatMeno();
// p1->setName("Jack");
// p1->setAge(21);
// p1->printD();
// p1->recover();
// p1->printD();
// delete p1;
// }
void test02(void){
Person *p1 = new Person("Tom", 18);
CareTaker *ca = new CareTaker(p1->creatMeno());
cout << "before: " << endl;
p1->printD();
p1->setName("Mark");
p1->setAge(27);
cout << "after: " << endl;
p1->printD();
p1->recover(ca->recover());
cout << "revover: "<< endl;
p1->printD();
}
int main(void){
// test01();
test02();
system("pause");
return 0;
}
5.8 訪問者模式#
訪問者(Visitor)模式的定義:將作用於某種數據結構中的各元素的操作分離出來封裝成獨立的類,使其在不改變數據結構的前提下可以添加作用於這些元素的新的操作,為數據結構中的每個元素提供多種訪問方式。它將對數據的操作與數據結構進行分離,是行為類模式中最複雜的一種模式。
邏輯思路圖如下:
示例代碼裡把數據結構 ParkElement 和數據操作 Visitor 分離出來,只需要 ParkElement 去接受 Visitor 子類對象對他的訪問就可以。代碼如下:
#include <iostream>
using namespace std;
#include <list>
class ParkElement;
class Visitor{
public:
virtual void visit(ParkElement *pm) = 0;
};
class ParkElement{
public:
virtual void accept(Visitor *visitor) = 0;
};
class ParkA: public ParkElement{
public:
virtual void accept(Visitor *visitor){
visitor->visit(this);
}
};
class ParkB: public ParkElement{
public:
virtual void accept(Visitor *visitor){
visitor->visit(this);
}
};
class Park: public ParkElement{
public:
Park(void){
m_list.clear();
}
void setParkElement(ParkElement *pe){
m_list.push_back(pe);
}
virtual void accept(Visitor *v){
for(list<ParkElement*>::iterator it = m_list.begin(); it!=m_list.end(); it++){
(*it)->accept(v);
}
}
private:
list<ParkElement*> m_list;
};
class VisitorA: public Visitor{
public:
virtual void visit(ParkElement *pm){
cout << "VisitorA is call" << endl;
}
};
class VisitorB: public Visitor{
public:
virtual void visit(ParkElement *pm){
cout << "VisitorB is call" << endl;
}
};
class Manager: public Visitor{
public:
virtual void visit(ParkElement *pm){
cout << "Manager visit" << endl;
}
};
// void test01(void){
// Visitor *v1 = new VisitorA;
// Visitor *v2 = new VisitorB;
// ParkElement *pm1 = new ParkA;
// ParkElement *pm2 = new ParkB;
// pm1->accept(v1);
// pm2->accept(v2);
// delete v1;
// delete v2;
// delete pm1;
// delete pm2;
// }
void test02(void){
Visitor *manager = new Manager;
ParkElement *p1 = new ParkA;
ParkElement *p2 = new ParkB;
ParkElement *p3 = new ParkA;
Park *parkAll = new Park;
parkAll->setParkElement(p1);
parkAll->setParkElement(p2);
parkAll->setParkElement(p3);
parkAll->accept(manager);
}
int main(void){
// test01();
test02();
system("pause");
return 0;
}
5.9 狀態模式#
狀態模式,又稱狀態對象模式(Pattern of