設計模式從本質上講,是針對過去某種經驗的總結。每種設計模式都是為了在特定條件下去解決某種問題。
設計模式中的每個模式描寫了1個在我們周圍不斷重復產生的問題,和該問題的解決方案的核心。這樣,你就可以1次又1次地使用該方案而沒必要做重復勞動。它是可復用面向對象軟件的基礎。
設計模式解決的是系統設計問題,設計模式是“術”,設計模式背后的意圖才是“道”。GoF提出了23中設計模式,是對平常用到的模式總結歸納出的,他們不是1盤散沙,是有關系的。就是對象的生命周期1步1步的將各個設計模式串連在了1起。對象的生命周期中,會1步1步的遇到總共23種設計問題,所以才會有23種設計模式。
Single Responsibility Principle, SRP:1個類只能有1個讓它變化的緣由,即1個類只承當1個職責。
Open-Close Principle, OCP:我們的設計應當對擴大開放,對修改封閉。即盡可能以擴大的方式來保護系統。如果遇到需求變化,要通過添加新的類來實現,而不是修改現有的代碼。
Liskov Subsititution Principle, LSP:子類可以完全覆蓋父類。它表示我們可以在代碼中使用任意子類來替換父類并且程序不受影響,這樣可以保證我們使用“繼承”并沒有破壞父類。
反過來則不成立,如果1個軟件實體使用的是1個子類對象的話,那末它不1定能夠使用基類對象。例如:我喜歡動物,那我1定喜歡狗,由于狗是動物的子類;但是我喜歡狗,不能據此判定我喜歡(所有)動物。
Interface Segregation Principle, ISP:每一個接口都實現單1的功能。使用多個專門的接口,而不使用單1的總接口。添加新功能時,要增加1個新接口,而不是修改已有的接口,制止出現“胖接口”。
Dependence Inversion Principle, DIP:這里主要是提倡“面向接口”編程,而非“面向實現”編程。具體依賴于抽象,而非抽象依賴于具體。即,要把不同子類的相同功能抽象出來,依賴與這個抽象,而不是依賴于具體的子類。
又稱最少知道原則(Demeter Principle)。最少知道原則是指:1個實體應當盡可能少地與其他實體之間產生相互作用,使得系統功能模塊相對獨立。
Composite Reuse Principle:盡可能使用合成/聚合的方式,而不是使用繼承。
根據模式的目的可分為:創建型、結構型、行動型3種。
1)創建型模式:與對象的創建有關;
2)結構型模式:處理類或對象的組合;
3)行動型模式:對類或對象怎樣交互和怎樣分配職責進行描寫。
1、 抽象工廠模式(Abstract Factory Pattern)
工廠(Factory )和產品(Product)是Abstract Factory 模式的主要參與者。該模式描寫了怎樣在不直接實例化類的情況下創建1系列相干的產品對象。
工廠方法模式通過引入工廠等級結構,解決了簡單工廠模式中工廠類職責太重的問題,但由于工廠方法模式中的每一個工廠只生產1類產品,可能會致使系統中存在大量的工廠類,必將會增加系統的開消。此時,我們可以斟酌將1些相干的產品組成1個“產品族”,由同1個工廠來統1生產,這就是抽象工廠模式的基本思想。
有時候我們希望1個工廠可以提供多個產品對象,而不是單1的產品對象,如1個電器工廠,它可以生產電視機、電冰箱、空調等多種電器,而不是只生產某1種電器。
每個具體工廠可以生產屬于1個產品族的所有產品。如果使用工廠方法模式,圖4所示結構需要提供15個具體工廠,而使用抽象工廠模式只需要提供5個具體工廠,極大減少了系統中類的個數。
2、 建造者模式(Builder Pattern)
又稱生成器模式。將1個復雜對象的構建與它的表示分離,使得一樣的構建進程可以創建不同的表示。為客戶端返回的不是1個簡單的產品,而是1個由多個部件組成的復雜產品。
它將客戶端與包括多個組成部份(或部件)的復雜對象的創建進程分離,客戶端不必知道復雜對象的內部組成部份與裝配方式,只需要知道所需建造者的類型便可。
建造者模式與抽象工廠模式有點類似,但是建造者模式返回1個完全的復雜產品,而抽象工廠模式返回1系列相干的產品;在抽象工廠模式中,客戶端通過選擇具體工廠來生成所需對象,而在建造者模式中,客戶端通過指定具體建造者類型并指點Director類如何去生成對象,側重于1步步構造1個復雜對象,然后將結果返回。如果將抽象工廠模式看成1個汽車配件生產廠,生成不同類型的汽車配件,那末建造者模式就是1個汽車組裝廠,通過對配件進行組裝返回1輛完全的汽車。
3、 原型模式(Prototype Pattern)
用原型實例指定創建對象的種類,并且通過拷貝這些原型來創建新的對象。通過1個原型對象克隆出多個1模1樣的對象。在使用原型模式時,我們需要首先創建1個原型對象,再通過復制這個原型對象來創建更多同類型的對象。
原型模式的工作原理很簡單:將1個原型對象傳給那個要發動創建的對象,這個要發動創建的對象通過要求原型對象拷貝自己來實現創建進程。
Prototype有許多和Abstract Factory和B u i l d e r1樣的效果:對客戶隱藏了具體的產品類,因此減少了客戶知道的名字的數目。另外,這些模式使客戶無需改變便可使用與特定利用相干的類。
另外1些優點:
1 ) 比其他創建型模式更加靈活,由于客戶可以在運行時刻建立和刪除原型。
2 ) 克隆1個原型類似于實例化1個類。可以極大的減少系統所需類的數目。
3) 改變結構以指定新對象。
4 ) 減少子類的構造。使得克隆1個原型而不是要求1個工廠方法去產生新的對象。
5) 用類動態配置利用。1些運行時刻環境允許你動態將類裝載到利用中。
主要缺點是每個Prototype的子類都必須實現Clone操作,這可能很困難。
4、 工廠方法模式(Factory Method Pattern)
介紹定義1個用于創建對象的接口,讓子類決定將哪個類實例化。Factory Method使1個類的實例化延遲到其子類。
工廠方法模式中,1種產品(1個產品類)對應1個工廠,針對不同的產品提供不同的工廠。
主要優點:用戶只需要關心所需產品對應的工廠,不必關心創建細節,乃至不必知道具體產品類的類名。 主要缺點:在添加新產品時,需要編寫新的具體產品類,而且還要提供與之對應的具體工廠類,系統中類的個數將成對增加,在1定程度上增加了系統的復雜度。
5、 單例模式(Singleton Pattern)
保證1個類唯一1個實例,并提供1個訪問它的全局訪問點。
Singleton模式有許多優點:
1) 對唯1實例的受控訪問。由于Singleton類封裝它的唯1實例,所以它可以嚴格的控制客戶怎樣和什么時候訪問它。
2) 縮小名空間。Singleton模式是對全局變量的1種改進。它避免了那些存儲唯1實例的全局變量污染名空間。
3) 允許對操作和表示的精化。Singleton類可以有子類,而且用這個擴大類的實例來配置1個利用是很容易的。你可以用你所需要的類的實例在運行時刻配置利用。
4) 允許可變數目的實例。可以用相同的方法來控制利用所使用的實例的數目。
使用Singleton模式所要斟酌的實現問題:
保證1個唯1的實例。做到這1點的1個經常使用方法是將創建這個實例的操作隱藏在1個類操作(即1個靜態成員函數或是1個類方法)后面,由它保證只有1個實例被創建。單例模式實現?。。。。?/strong>
//Singleton類定義以下:
class Singleton{
public:
//客戶只能使用該成員函數訪問這個單例
static Singleton* Instance();//靜態方法,保證只創建1個實例
protected:
//構造函數為保護型,試圖直接實例化Singleton將會編譯毛病
Singleton();//這就保證了唯一1個實例可以被創建
private:
//Singleton類型的指針,將用于指向Singleton的唯1的實例
static Singleton* _instance;
};
//相應的實現
Singleton* Singleton::_instance=0;//靜態數據成員初始化
Singleton* Singleton::Instance(){
if(_instance==0){//只在首次創建
_instance = new Singleton;
}
return _intance;
}
實例講授:在Windows系統中屢次點擊“啟動任務管理器”,看能否打開多個任務管理器窗口?不管我們啟動任務管理多少次,Windows系統始終只能彈出1個任務管理器窗口,也就是說在1個Windows系統中,任務管理器存在唯1性。為了確保對象的唯1性,我們可以通過單例模式來實現,這就是單例模式的動機所在。
6、 適配器模式(Adapter Pattern)
將1個類的接口轉換成客戶希望的另外1個接口。Adapter模式使得本來由于接口不兼容而不能1起工作的那些類可以1起工作。
適配器模式中引入了1個被稱為適配器(Adapter)的包裝類,而它所包裝的對象稱為適配者(Adaptee),即被適配的類。適配器的實現就是把客戶類的要求轉化為對適配者的相應接口的調用。也就是說:當客戶類調用適配器的方法時,在適配器類的內部將調用適配者類的方法,而這個進程對客戶類是透明的,客戶類其實不直接訪問適配者類。
Adapter對Adaptee和Target進行適配,在對象適配器中,它通過繼承Target并關聯1個Adaptee對象使2者產生聯系。
適配器模式的類圖:
如圖客戶端需要調用request()方法,而適配者類Adaptee沒有該方法,但是它所提供的specificRequest()方法卻是客戶端所需要的。為了使客戶端能夠使用適配者類,需要提供1個包裝類Adapter,即適配器類。這個包裝類包裝了1個適配者的實例,從而將客戶端與適配者銜接起來,在適配器的request()方法中調用適配者的specificRequest()方法。
對象適配器實現以下:!?。?!
#include <iostream>
using namespace std;
class Target
{
public:
Target(){}
virtual ~Target(){}
virtual void Request()
{
cout<<"Target::Request"<<endl;
}
};
class Adaptee
{
public:
void SpecificRequest()
{
cout<<"Adaptee::SpecificRequest"<<endl;
}
};
class Adapter : public Target
{
public:
Adapter() : m_Adaptee(new Adaptee) {}
~Adapter()
{
if (m_Adaptee != NULL)
{
delete m_Adaptee;
m_Adaptee = NULL;
}
}
void Request()
{
m_Adaptee->SpecificRequest();
}
private:
Adaptee *m_Adaptee;
};
int main()
{
Target *targetObj = new Adapter();//基類指針指向子類對象
targetObj->Request();調用適配后的Request()方法
delete targetObj;
targetObj = NULL;
return 0;
}
實例講授:
我的筆記本電腦的工作電壓是20V,而我國的家庭用電是220V,如何讓20V的筆記本電腦能夠在220V的電壓下工作?答案是引入1個電源適配器(AC Adapter),俗稱充電器,有了它,生活用電和筆記本電腦便可兼容。
7、 橋接模式(Bridge Pattern)
可以將抽象部份與它的實現部份分離,使它們都可以獨立地變化。
Bridge模式的目的就是允許分離的類層次1起工作,即便它們是獨立演變的。
如果軟件系統中某個類存在兩個獨立變化的維度,通過該模式可以將這兩個維度分離出來,使二者可以獨立擴大,讓系統更加符合“單1職責原則”。
橋接模式用1種奇妙的方式處理多重繼承存在的問題,用抽象關聯取代了傳統的多重繼承,將類之間的靜態繼承關系轉換為動態的對象組合關系,使得系統更加靈活,并易于擴大,同時有效控制了系統中類的個數。
使用橋接模式實例:兩個維度(毛筆大小和毛筆色彩)分開。針對兩個不同的維度提取抽象類和實現類接口,并建立1個抽象關聯關系。
上圖中,如果需要增加1種新型號的毛筆,只需擴大左邊的“抽象部份”,增加1個新的擴充抽象類;如果需要增加1種新的色彩,只需擴大右邊的“實現部份”,增加1個新的具體實現類。
8、 組合模式(Composite Pattern)
組合模式描寫了面向對象遞歸組合的本質。
將對象組合成樹形結構以表示“部份-整體”的層次結構。它使得客戶對單個對象和復合對象的使用具有1致性。
組合模式的關鍵是定義了1個抽象構件類,它既可以代表葉子,又可以代表容器,而客戶端針對該抽象構件類進行編程,不必知道它到底表示的是葉子還是容器,可以對其進行統1處理。!??!
9、 裝潢模式(Decorator Pattern)
動態地給1個對象添加1些額外的職責。就擴大功能而言,它比生成子類方式更加靈活。
裝潢模式可以在不改變1個對象本身功能的基礎上給對象增加額外的新行動。對已有對象(新居)的功能進行擴大(裝修),以取得更加符適用戶需求的對象,使得對象具有更加強大的功能。
10、 外觀模式(Facade Pattern)
為子系統中的1組接口提供1個1致的界面,Facade模式定義了1個高層接口,這個接口使得這1子系統更加容易使用。
在軟件開發中,有時1個客戶類需要和多個業務類交互,特別需要1個類似服務員1樣的角色,由它來負責和多個業務類進行交互,而客戶類只需與該類交互。外觀模式通過引入1個新的外觀類(Facade)來實現該功能,外觀類充當了軟件系統中的“服務員”,它為多個業務類的調用提供了1個統1的入口,簡化了類與類之間的交互。下降了系統的耦合度。!?。。?
11、 享元模式(Flyweight Pattern)
應用同享技術有效地支持大量細粒度的對象。
將具有相同內部狀態的對象存儲在享元池中,享元池中的對象是可以實現同享的,需要的時候就將對象從享元池中取出,實現對象的復用。
避免系統中出現大量相同或類似的對象,同時又不影響客戶端程序通過面向對象的方式對這些對象進行操作。享元模式正為解決這1類問題而誕生。享元模式通過同享技術實現相同或類似對象的重用,在邏輯上每個出現的字符都有1個對象與之對應,但是在物理上它們卻同享同1個享元對象。
12、 代理模式(Proxy Pattern)
介紹為其他對象提供1個代理以控制對這個對象的訪問。
當沒法直接訪問某個對象或訪問某個對象存在困難時可以通過1個代理對象來間接訪問,為了保證客戶端使用的透明性,所訪問的真實對象與代理對象需要實現相同的接口。
代理模式的共同優點以下:
(1) 能夠調和調用者和被調用者,在1定程度上下降了系統的耦合度。
(2) 客戶端可以針對抽象主題角色進行編程,增加和更換代理類不必修改源代碼,符合開閉原則,系統具有較好的靈活性和可擴大性。
另外,不同類型的代理模式也具有獨特的優點,例如:
(1) 遠程代理為位于兩個不同地址空間對象的訪問提供了1種實現機制,可以將1些消耗資源較多的對象和操作移至性能更好的計算機上,提高系統的整體運行效力。
(2) 虛擬代理通過1個消耗資源較少的對象來代表1個消耗資源較多的對象,可以在1定程度上節省系統的運行開消。
(3) 緩沖代理為某1個操作的結果提供臨時的緩存存儲空間,以便在后續使用中能夠同享這些結果,優化系統性能,縮短履行時間。
(4) 保護代理可以控制對1個對象的訪問權限,為不同用戶提供不同級別的使用權限。
代理模式的主要缺點以下:
(1) 由于在客戶端和真實主題之間增加了代理對象,因此有些類型的代理模式可能會造成要求的處理速度變慢,例如保護代理。
(2) 實現代理模式需要額外的工作,而且有些代理模式的實現進程較為復雜,例如遠程代理。
13、 責任鏈模式(Chain of Responsibility Pattern)
為消除要求的發送者和接收者之間耦合,而使多個對象都有機會處理這個要求。將這些對象連成1條鏈,并沿著這條鏈傳遞該要求,直到有1個對象處理它。
14、 命令模式(Command Pattern)
該模式描寫了怎樣封裝要求,也描寫了1致性的發送要求的接口,允許你配置客戶端以處理不同要求。對要求排隊或記錄要求日志,和支持可取消的操作。
15、 解釋器模式(Interpreter Pattern)
給定1個語言,定義它的文法的1種表示,并定義1個解釋器, 該解釋器使用該表示來解釋語言中的句子。
16、 迭代器模式(Iterator Pattern)
支持訪問和遍歷對象結構。不但可用于組合結構也可用于集合。介紹提供1種方法順序訪問1個聚合對象中各個元素, 而又不需暴露該對象的內部表示。
17、 中介者模式(Mediator Pattern)
介紹用1個中介對象來封裝1系列的對象交互。中介者使各對象不需要顯式地相互援用,從而使其耦合疏松,而且可以獨立地改變它們之間的交互。
18、 備忘錄模式(Memento Pattern)
介紹在不破壞封裝性的條件下,捕獲1個對象的內部狀態,并在該對象以外保存這個狀態。這樣以后便可將該對象恢復到保存的狀態。
19、 視察者模式(Observer Pattern)
介紹定義對象間的1種1對多的依賴關系,以便當1個對象的狀態產生改變時,所有依賴于它的對象都得到通知并自動刷新。
20、 狀態模式(State Pattern)
介紹允許1個對象在其內部狀態改變時改變它的行動。對象看起來仿佛修改了它所屬的類。
21、 策略模式(Strategy Pattern)
在對象中封裝算法是策略模式的目的。允許不同的格式化算法。
介紹定義1系列的算法,把它們1個個封裝起來,并且使它們可相互替換。本模式使得算法的變化可獨立于使用它的客戶。
模式的主要參與者是Strategy對象(這些對象中封裝了不同的算法)和它們的操作環境。Strategy模式利用的關鍵點在于為Strategy和它的環境設計足夠通用的接口,以支持1系列的算法。你沒必要為了支持1個新的算法而改變Strategy或它的環境。
22、 模板方法模式(Template Method Pattern)
介紹定義1個操作中的算法的骨架,而將1些步驟延遲到子類中。Template Method使得子類可以不改變1個算法的結構便可重定義該算法的某些特定步驟。
主要解決在軟件構建進程中,對某1項任務,常常有穩定的整體操作結構,但各個子步驟卻有很多改變的需求,或由于固有的緣由而沒法和任務的整體結構同時實現。
23、 訪問者模式(Visitor Pattern)
介紹表示1個作用于某對象結構中的各元素的操作。它使你可以在不改變各元素的類的條件下定義作用于這些元素的新操作。
它允許對圖元結構所作分析的數目不受限制地增加而沒必要改變圖元類本身。
訪問者類的另外一個優點是它不局限使用于像圖元結構這樣的組合者,也適用于其他任何對象結構。包括集合、列表,乃至無環有向圖。再者,訪問者所能訪問的類之間無需通過1個公共父類關聯起來。也就是說,訪問者能逾越類層次結構。
參考:
《設計模式》
http://blog.csdn.net/lovelion
上一篇 第四章 內建組件
下一篇 [Java]ITOO初步了解