設計模式基礎
模式
- 在一定環境中解決某一問題的方案,包括三個基本元素–問題,解決方案和環境。
- 大白話:在一定環境下,用固定套路解決問題。
設計模式
是一套被反復使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計 模式是為了可重用代碼、讓代碼更容易被他人理解、保證代 碼可靠性。 毫無疑問,設計模 式于己于他人于系統都是多贏的;設計模式使代碼編制真正工程化;
設計模式是軟件工程的基石脈絡,如同大廈的結構一樣。
設計模式分類
GangofFour 的“DesignPatterns:ElementsofResualbelSoftware”書將設計模式歸納為 三大類型,共 23 種。
- 創建型模式 : 通常和對象的創建有關,涉及到對象實例化的方式。(共 5 種模式)
- 結構型模式: 描述的是如何組合類和對象以獲得更大的結構。(共 7 種模式)
- 行為型模式: 用來對類或對象怎樣交互和怎樣分配職責進行描述。(共 11 種模式)
創建型模式
用來處理對象的創建過程
工廠方法模式(FactoryMethodPattern)
定義一個創建產品對象的工廠接口, 將實際創建工作推遲到子類中。
抽象工廠模式(AbstractFactoryPattern)
提供一個創建一系列相關或者相互依 賴的接口,而無需指定它們具體的類。
建造者模式(BuilderPattern)
將一個復雜的構建與其表示相分離,使得同樣的 構建過程可以創建不同的表示。
原型模式(PrototypePattern
用原型實例指定創建對象的種類,并且通過拷貝這些原型創建新的對象。
單例模式(SingletonPattern)
是保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。
結構型模式
處理類或者對象的組合
代理模式(ProxyPattern)
為其他對象提供一種代理以控制對這個對象的訪問
裝飾者模式(DecoratorPattern)
給一個對象添加一些額外的職責。就增加功能來 說,此模式比生成子類更為靈活。
適配器模式(AdapterPattern)
將一個類的接口轉換成客戶希望的另外一個接口。使得 原本由于接口不兼容而不能一起工作的那些類可以一起工作
橋接模式(BridgePattern)
將抽象部分與實際部分分離,使它們都可以獨立的變化。
組合模式(CompositePattern)
將對象組合成樹形結構以表示“部分–整體”的層次結 構。使得用戶對單個對象和組合對象的使用具有一致性
外觀模式(FacadePattern)
為子系統中的一組接口提供一個一致的界面,此模式定義 了一個高層接口,這個接口使得這一子系統更加容易使用
享元模式(FlyweightPattern)
以共享的方式高效的支持大量的細粒度的對象。
行為型模式
用來對類或對象怎樣交互和怎樣分配職責進行描述
模板方法模式(TemplateMethodPattern)
使得子類可以不改變一個算法的結構即可重 定義該算法的某些特定步驟。
命令模式(CommandPattern)
將一個請求封裝為一個對象,從而使你可用不同的請 求對客戶端進行參數化;對請求排隊或記錄請求日志,以及支持可撤銷的操作
責任鏈模式(ChainofResponsibilityPattern)
在該模式里,很多對象由每一個對象對其 下家的引用而連接起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理 此請求,這使得系統可以在不影響客戶端的情況下動態地重新組織鏈和分配責任
策略模式(StrategyPattern)
是準備一組算法,并將每一個算法封裝起來,使得它們 可以互換。
中介者模式(MediatorPattern)
定義一個中介對象來封裝系列對象之間的交互。終 結者使各個對象不需要顯示的相互調用 ,從而使其耦合性松散,而且可以獨立的改變他們 之間的交互。
觀察者模式(ObserverPattern)
定義對象間的一種一對多的依賴關系,當一個對象的狀 態發生改變時,所有依賴于它的對象都得到通知并被自動更新。
備忘錄模式(MementoPattern)
是在不破壞封裝的前提下,捕獲一個對象的內部狀態, 并在該對象之外保存這個狀態。
訪問者模式(VisitorPattern)
就是表示一個作用于某對象結構中的各元素的操作,它使 你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。
狀態模式(StatePattern)
對象的行為,依賴于它所處的狀態
解釋器模式(InterpreterPattern)
描述了如何為簡單的語言定義一個語法,如何在 該語言中表示一個句子,以及如何解釋這些句子。
迭代器模式(IteratorPattern)
提供了一種方法順序來訪問一個聚合對象中的各個元 素,而又不需要暴露該對象的內部表示。
設計模式基本原則
最終目的:高內聚,低耦合
開放封閉原則 (OCP,OpenForExtension,ClosedForModificationPrinciple)
類的改動是通過增加代碼進行的,而不是修改源代碼。
#include<iostream>using namespace std;
//開閉原則//寫一個抽象類
class AbstractCaculator
{
public:virtual int getResult() = 0;virtual void setOperatorNumber(int a, int b) = 0;};//加法計算器
class PlusCaculator :public AbstractCaculator{
public:virtual void setOperatorNumber(int a, int b){this->mA = a;this->mB = b;}virtual int getResult(){return mA + mB;}
private:int mA;int mB;
};//減法計算器
class MinuteCaculator :public AbstractCaculator{
public:virtual void setOperatorNumber(int a, int b){this->mA = a;this->mB = b;}virtual int getResult(){return mA - mB;}
private:int mA;int mB;
};//乘法計算器
class MultiplyCaculator :public AbstractCaculator{
public:virtual void setOperatorNumber(int a, int b){this->mA = a;this->mB = b;}virtual int getResult(){return mA * mB;}
private:int mA;int mB;
};void test01()
{//父類指針指向基類對象AbstractCaculator * caculator = new PlusCaculator;caculator->setOperatorNumber(10, 20);cout << "ret:" << caculator->getResult() << endl;caculator = new MultiplyCaculator;caculator->setOperatorNumber(30,20);cout << "ret:" << caculator->getResult() << endl;
}int main(void)
{test01();system("pause");return 0;
}
我們如果想再次增加計算器類型,只用繼承基類,重寫方法就可以了。
單一職責原則 (SRP,SingleResponsibilityPrinciple)
類的職責要單一,對外只提供一種功能,而引起類變化的原因都應該只有一個。
依賴倒置原則 (DIP,DependenceInversionPrinciple)
依賴于抽象(接口),不要依賴具體的實現(類),也就是針對接口編程。
#include<iostream>
using namespace std;class BankWorker{
public:void SaveService(){cout << "辦理存款業務..." << endl;}void payService(){cout << "辦理支付業務.." << endl;}void tranferService(){cout << "辦理轉賬業務..." << endl;}
};void doSaveBussiness(BankWorker *worker){worker->SaveService();
}
void doPayBussiness(BankWorker *worker){worker->payService();
}
void doTransferBussiness(BankWorker *worker){worker->tranferService();
}void test01(){BankWorker *worker = new BankWorker;doSaveBussiness(worker);//辦理存款業務doPayBussiness(worker);//辦理支付業務doTransferBussiness(worker);//辦理轉賬業務
}int main(void)
{system("pause");return 0;
}
//銀行工作人員
class AbstractWotker{
public:virtual void doBussiness() = 0;};//專門負責辦理存款業務的工作人員
class doSaveBankWorker :public AbstractWotker{
public:virtual void doBussiness(){cout << "辦理存款業務.." << endl;}
};class PaySaveBankWorker :public AbstractWotker{
public:virtual void doBussiness(){cout << "辦理支付業務.." << endl;}
};class TransferSaveBankWorker :public AbstractWotker{
public:virtual void doBussiness(){cout << "辦理轉賬業務.." << endl;}
};//中層業務,依賴于抽象層,bu
void doNewBusiness(AbstractWotker * worker){worker->doBussiness();delete worker;
}void test02()
{doNewBusiness(new TransferSaveBankWorker);doNewBusiness(new doSaveBankWorker);doNewBusiness(new PaySaveBankWorker);
}int main(void)
{//test01();system("pause");return 0;
}
接口隔離原則 (ISP,InterfaceSegegationPrinciple)
不應該強迫客戶的程序依賴他們不需要的接口方法。一個接口應該只提供一種對外功能, 不應該把所有操作都封裝到一個接口中去。
里氏替換原則 (LSP,LiskovSubstitutionPrinciple)
任何抽象類出現的地方都可以用他的實現類進行替換。實際就是虛擬機制,語言級別實 現面向對象功能。
合成復用原則(CARP,Composite/AggregateReusePrinciple)
優先使用組合而不是繼承原則。如果使用繼承,會導致父類的任何變換都可能影響到子類的行為。 如果使用對象組合,就降低了這種依賴關系。
#include<iostream>
using namespace std;class AbstractCar{
public:virtual void run() = 0;};class Dazhong :public AbstractCar{
public:virtual void run(){cout << "大眾車啟動..." << endl;}
};class Tuolaji :public AbstractCar{
public:virtual void run(){cout << "拖拉機啟動.." << endl;}
};//針對具體類,不使用繼承
#if 0
class Person :public Tuolaji{
public:void Doufeng(){run();}
};class PersonB :public Tuolaji{
public:void Doufeng(){run();}
};
#endif//用組合
class Person{
public:/*~Person(){if (this->car != NULL){delete this->car;}}*/void setCar(AbstractCar *car){this->car = car;}void Doufeng(){this->car->run();if (this->car != NULL){delete this->car;this->car = NULL;}}public:AbstractCar *car;
};void test02(){Person* p = new Person;p->setCar(new Dazhong);p->Doufeng();p->setCar(new Tuolaji);p->Doufeng();delete p;
}//繼承和組合優先使用組合
int main()
{test02();system("pause");return 0;
}
迪米特法則(LOD,LawofDemeter)
一個對象應當對其他對象盡可能少的了解,從而降低各個對象之間的耦合,提高系統的 可維護性。例如在一個程序中,各個模塊之間相互調用時,通常會提供一個統一的接口來實 現。這樣其他模塊不需要了解另外一個模塊的內部實現細節,這樣當一個模塊內部的實現發 生改變時,不會影響其他模塊的使用。
#include<iostream>
#include<string>
#include<vector>
using namespace std;
//迪米特原則,又叫最小知識原則,不要暴露內部結構,只提供接口class AbstractBuiding
{
public:virtual void sale() = 0;virtual string getQuality() = 0;
};//樓盤A
class BuildingA :public AbstractBuiding
{
public:BuildingA(){mQuity = "高品質";}virtual void sale(){cout << "樓盤A" << mQuity << "被售賣";}virtual string getQuality(){return mQuity;}
public:string mQuity;
};//樓盤B
class BuildingB :public AbstractBuiding
{
public:BuildingB(){mQuity = "低品質";}virtual void sale(){cout << "樓盤B" << mQuity << "被售賣";}virtual string getQuality(){return mQuity;}
public:string mQuity;
};
#if 0
void test01()
{BuildingA * ba = new BuildingA;if (ba->mQuity == "低品質"){ba->sale();}BuildingB *bb = new BuildingB;if (bb->mQuity == "低品質"){bb->sale();}
}
#endif//中介類
class Mediator{
public:Mediator(){AbstractBuiding * building = new BuildingA;vBuilding.push_back(building);building = new BuildingB;vBuilding.push_back(building);}~Mediator(){for (vector<AbstractBuiding*>::iterator it = vBuilding.begin(); it != vBuilding.end(); it++){if (*it != NULL){delete *it;}}}//對外提供接口AbstractBuiding *findMyBuilding(string qulity){for (vector<AbstractBuiding *>::iterator it = vBuilding.begin(); it != vBuilding.end(); it++){if ((*it)->getQuality() == qulity){return *it;}}return NULL;}
public:vector<AbstractBuiding*>vBuilding;
};void test02()
{Mediator *mediator = new Mediator;AbstractBuiding*building = mediator->findMyBuilding("高品質");if (building != NULL){building->sale();}else{cout << "沒有符合您條件的樓盤!" << endl;}
}int main(void)
{//test01();test02();system("pause");return 0;
}
就是有個中間商。