C++進階(語法篇)—第11章 設計模式(3)
11.3.4模板模式
模板模式:定義一個操作中的演算法骨架,將一些步驟延遲到子類中。模板模式使得子類可以不改變一個演算法的介面即可重定義該演算法的某些特定步驟。
模板模式是行為型模式中最簡單的一種,在實際應用中會經常使用。注:模板模式和前面的類/函式模板不同。
案例:現在公司組2個隊伍,一個隊伍打羽毛球,一個隊伍打籃球,請完成這個程式的設計。
#include <iostream>
using namespace std;
class Sport
{
protected:
virtual bool
virtual bool prepareEquipment(void) = 0;
public:
virtual void startGame(void) = 0;
};
class Basketball:public Sport
{
protected:
bool organizeTeam(void)
{
cout << "籃球隊5人組隊完成" << endl;
return 1;
}
bool prepareEquipment(void)
{
cout << "籃球已準備好" << endl;
return 1;
}
public:
void startGame(void)
{
if (organizeTeam() && prepareEquipment())
cout << "開始籃球比賽" << endl;
}
};
class Badminton :public Sport
{
protected:
bool organizeTeam(void)
{
cout << "羽毛球隊2人組隊完成" << endl;
return 1;
}
bool prepareEquipment(void)
{
cout << "羽毛球拍和羽毛球已準備好" << endl;
return 1;
}
public:
void startGame(void)
{
if (organizeTeam() && prepareEquipment())
cout << "開始羽毛球比賽" << endl;
}
};
int main(int argc, char ** argv)
{
Basketball bas;
bas.startGame();
Badminton badm;
badm.startGame();
return 0;
}
執行結果:
籃球隊5人組隊完成
籃球已準備好
開始籃球比賽
羽毛球隊2人組隊完成
羽毛球拍和羽毛球已準備好
開始羽毛球比賽
模板模式結構圖:
AbstractClass:抽象類,定義演算法的框架。
ConcreteClass:具體類,實現框架中的演算法。
11.4結構型模式
結構型模式:通過不同類、物件的組合,來簡化設計。結構型設計模式的準則:多用組合,少用繼承。主要講介面卡模式、橋接模式、裝飾者模式、組合模式、外觀模式、代理模式。
11.4.1介面卡模式
介面卡模式:將一個類的介面轉換成客戶希望的另一個介面,使得原本不相容的介面可以正常工作。介面卡模式分為2種:類的介面卡,物件介面卡(常用)。
案例:你在機場候機時,手機電量不足需要充電,但是機場只有三孔的插座,而你的充電器是兩腳充電器,因此需要一個三腳的排插才可以充電。請完成這個程式的設計。
//類的介面卡:多繼承方式
#include <iostream>
using namespace std;
//三孔插座
class ThreeSocket
{
public:
virtual ~ThreeSocket() {}
virtual void Charge(void)
{
cout << "連線三腳充電器..." << endl;
}
};
//雙腳充電器
class TwoCharger
{
public:
virtual ~TwoCharger() {}
void startCharge()
{
cout << "開始充電" << endl;
}
};
//介面卡:三腳排插
class ThreeIntercalation:public ThreeSocket,public TwoCharger
{
public:
virtual void Charge(void)
{
startCharge();
}
};
int main(int argc, char ** argv)
{
ThreeIntercalation ti;
ti.Charge();
return 0;
}
//物件介面卡:物件組合方式
#include <iostream>
using namespace std;
//三孔插座
class ThreeSocket
{
public:
virtual ~ThreeSocket() {}
virtual void Charge(void)
{
cout << "連線三腳充電器..." << endl;
}
};
//雙腳充電器
class TwoCharger
{
public:
virtual ~TwoCharger() {}
void startCharge()
{
cout << "開始充電" << endl;
}
};
//介面卡:三腳排插
class ThreeIntercalation:public ThreeSocket
{
private:
TwoCharger * tc;
public:
virtual void Charge(void)
{
tc->startCharge();
}
};
int main(int argc, char ** argv)
{
ThreeIntercalation ti;
ti.Charge();
return 0;
}
執行結果:
開始充電
類介面卡結構圖:
物件介面卡結構圖:
Target:目標介面,相當於三孔插座;
Adaptee:適配者,相當於雙腳充電器;
Adapter:介面卡,相當於三腳排插。
11.4.2橋接模式
橋接模式:將抽象部份與它的實現部份分離,使它們都可以獨立地變化。舉例:給手機(華為,蘋果)安裝軟體(微信,QQ)。程式碼如下:
#include <iostream>
using namespace std;
class Phone
{
public:
virtual void PhoneType(void) = 0;
};
class Huawei:public Phone
{
public:
void PhoneType(void)
{
cout << "華為手機" << endl;
}
};
class Apple :public Phone
{
public:
void PhoneType(void)
{
cout << "蘋果手機" << endl;
}
};
class Software
{
public:
virtual void printinfo() = 0;
};
class WeChat:public Software
{
public:
virtual void printinfo()
{
cout << "微信" << endl;
}
};
class QQ:public Software
{
public:
virtual void printinfo()
{
cout << "QQ" << endl;
}
};
class HuaweiWithWeChat :public Huawei,public WeChat
{
public:
void InstallSoftware(void)
{
cout << "華為手機開始安裝微信" << endl;
}
};
class HuaweiWithQQ :public Huawei, public QQ
{
public:
void InstallSoftware(void)
{
cout << "華為手機開始安裝微信" << endl;
}
};
class AppleWithWeChat :public Apple, public WeChat
{
public:
void InstallSoftware(void)
{
cout << "蘋果手機開始安裝微信" << endl;
}
};
class AppleWithQQ :public Apple, public QQ
{
public:
void InstallSoftware(void)
{
cout << "蘋果手機開始安裝QQ" << endl;
}
};
int main(int argc, char ** argv)
{
HuaweiWithWeChat hwc;
hwc.InstallSoftware();
return 0;
}
通過這樣的方式來編寫程式碼,產生了太多的派生類,因此採用橋接模式。
#include <iostream>
using namespace std;
class Phone
{
public:
virtual void PhoneType(void) = 0;
};
class Huawei:public Phone
{
public:
void PhoneType(void)
{
cout << "華為手機" << endl;
}
};
class Apple :public Phone
{
public:
void PhoneType(void)
{
cout << "蘋果手機" << endl;
}
};
class Software
{
public:
virtual void printinfo() = 0;
};
class WeChat:public Software
{
public:
virtual void printinfo()
{
cout << "微信" << endl;
}
};
class QQ:public Software
{
public:
virtual void printinfo()
{
cout << "QQ" << endl;
}
};
class HuaweiInstall:public Huawei
{
private:
Software * sw;
public:
HuaweiInstall(Software * sw):sw(sw)
{}
~HuaweiInstall() {}
void InstallSoftware(void)
{
cout << "華為手機開始安裝軟體" << endl;
}
};
class AppleInstall :public Apple
{
private:
Software * sw;
public:
AppleInstall(Software * sw) :sw(sw)
{}
~AppleInstall() {}
void InstallSoftware(void)
{
cout << "蘋果手機開始安裝軟體" << endl;
}
};
int main(int argc, char ** argv)
{
WeChat * wec = new WeChat;
HuaweiInstall hi(wec);
hi.InstallSoftware();
delete wec;
return 0;
}
執行結果:
華為手機開始安裝軟體
橋接模式的本質是將多繼承方式轉換為物件組合方式。這種方式減少了派生類的產生,便於程式碼的設計。
橋接模式結構圖:
11.4.3裝飾者模式
裝飾者模式:在不改變原類檔案和繼承的情況下,動態的擴充套件一個物件的功能。
案例:日常使用的手機種類很多,有華為手機、蘋果手機等,若我們想要給手機配上手機殼、掛件、耳機等,那該如何實現。
#include <iostream>
#include <string>
using namespace std;
class Phone
{
public:
~Phone() {}
virtual string pName(void) = 0;
};
class Huawei:public Phone
{
public:
~Huawei() {}
virtual string pName(void)
{
return "Huawei";
}
};
class Apple :public Phone
{
public:
~Apple() {}
virtual string pName(void)
{
return "Apple";
}
};
//裝飾品
class PhoneDecorator :public Phone
{
protected:
Phone * pPho;
public:
PhoneDecorator(Phone * pPho) :pPho(pPho) {}
~PhoneDecorator() {}
virtual string pName(void)
{
return pPho->pName() + " PhoneDecorator";
}
};
//手機殼
class PhoneShell :public PhoneDecorator
{
public:
PhoneShell(Phone * pPho) :PhoneDecorator(pPho) {}
~PhoneShell() {}
virtual string pName(void)
{
return pPho->pName() + " PhoneShell";
}
};
//手機掛機
class PhonePendant :public PhoneDecorator
{
public:
PhonePendant(Phone * pPho) :PhoneDecorator(pPho) {}
~PhonePendant() {}
virtual string pName(void)
{
return pPho->pName() + " PhonePendant";
}
};
//手機耳機
class PhoneHeadset :public PhoneDecorator
{
public:
PhoneHeadset(Phone * pPho) :PhoneDecorator(pPho) {}
~PhoneHeadset() {}
virtual string pName(void)
{
return pPho->pName() + " PhoneHeadset";
}
};
int main(int argc, char ** argv)
{
//華為手機
Huawei * hw = new Huawei;
//華為手機+手機殼
PhoneDecorator * ps = new PhoneShell(hw);
cout << ps->pName() << endl;
//華為手機+手機殼+掛機
PhoneDecorator * ph = new PhonePendant(ps);
cout << ph->pName() << endl;
delete hw;
delete ps;
delete ph;
return 0;
}
執行結果:
Huawei PhoneShell
Huawei PhoneShell PhonePendant
裝飾者模式結構圖:
Component:抽象元件;
ConcreteComponent:具體元件;
Decorator:抽象裝飾品;
ConcreteDecorator:具體裝飾品。
11.4.4外觀模式
外觀模式:為子系統中的一組介面提供一個統一的高層介面,該介面使子系統的使用更加簡單方便。
在vs中點選編譯,在編譯器內部分為4個步驟:預處理、編譯、彙編、連結。
#include <iostream>
using namespace std;
class Pretreatment
{
public:
void Run(void)
{
cout << "Pretreatment" << endl;
}
};
class Compile
{
public:
void Run(void)
{
cout << "Compile" << endl;
}
};
class Assemble
{
public:
void Run(void)
{
cout << "Assemble" << endl;
}
};
class Link
{
public:
void Run(void)
{
cout << "Link" << endl;
}
};
class CompileInterface
{
private:
Pretreatment pre;
Compile com;
Assemble ass;
Link li;
public:
void Run(void)
{
pre.Run();
com.Run();
ass.Run();
li.Run();
}
};
int main(int argc, char ** argv)
{
CompileInterface ci;
ci.Run();
return 0;
}
執行結果:
Pretreatment
Compile
Assemble
Link
外觀模式結構圖:
Facade:外觀;Subsystem:子系統。
11.4.5組合模式
組合模式:將物件組合成樹狀結構來表示“整體-部分”層次結構。
例項:一個公司,有自己直屬的財務部、工程部,它的整個結構就是一個樹形結構。
#include <iostream>
#include <string>
#include <list>
using namespace std;
class Company
{
public:
virtual ~Company() {}
virtual void printinfo(void) = 0;
};
//具體公司
class ConcreteCompany:public Company
{
private:
string name;
list<Company *> pCompanys;
public:
ConcreteCompany(string name) :name(name) {}
virtual ~ConcreteCompany() {}
void AddCompany(Company * comp)
{
pCompanys.push_back(comp);
}
void DeleteCompany(Company * comp)
{
pCompanys.remove(comp);
}
void printinfo(void)
{
cout << name << endl;
for (list<Company *>::iterator it = pCompanys.begin(); it != pCompanys.end(); ++it)
{
(*it)->printinfo();
}
}
};
//具體部門
class ConcreteDepartment :public Company
{
private:
string name;
public:
ConcreteDepartment(string name) :name(name) {}
virtual ~ConcreteDepartment() {}
void printinfo(void)
{
cout << name << endl;
}
};
int main(int argc, char ** argv)
{
ConcreteCompany * head_office = new ConcreteCompany("總公司");
Company * finance = new ConcreteDepartment("財務部");
Company * engineering = new ConcreteDepartment("工程部");
head_office->AddCompany(finance);
head_office->AddCompany(engineering);
head_office->printinfo();
cout << "刪除工程部:" << endl;
head_office->DeleteCompany(engineering);
head_office->printinfo();
return 0;
}
執行結果:
總公司
財務部
工程部
刪除工程部:
總公司
財務部
組合模式結構圖:
Component:抽象元件,相當於程式碼中的Company類;
Composite:容器元件,相當於程式碼中的ConcreteCompany類;
Leaf:葉子元件,相當於程式碼中的ConcreteDepartment類。
組合模式分為透明組合模式和安全組合模式。透明組合模式是在Component中定義用於管理和訪問容器、葉子元件的介面,優點是可以確保所有元件都有相同的介面。安全組合模式是在Component中不定義任何管理和訪問容器、葉子元件的介面,而在Composite中實現。
11.4.6代理模式
代理模式:為其他物件提供一種代理,以控制這個物件的訪問。代理物件在客戶和目標物件之間起到中介的作用。
例項:蘋果的A12晶片由臺積電代工。
#include <iostream>
using namespace std;
class A12chip
{
public:
virtual void printinfo(void) = 0;
virtual ~A12chip() {}
};
class Apple:public A12chip
{
public:
virtual void printinfo(void)
{
cout << "A12chip" << endl;
}
virtual ~Apple() {}
};
class TSMC :public A12chip
{
private:
Apple * pApple;
public:
TSMC(Apple * pApple) :pApple(pApple) {}
virtual void printinfo(void)
{
pApple->printinfo();
}
virtual ~TSMC() {}
};
int main(int argc, char ** argv)
{
Apple * pApple = new Apple;
TSMC tsmc(pApple);
tsmc.printinfo();
delete pApple;
return 0;
}
執行結果:
A12chip
代理模式結構圖:
Subject:抽象角色;Realsubject:真實角色;Proxy:代理角色。