設計模式之職責鏈模式(Chain of Responsibility)摘錄
23種GOF設計模式一般分為三大類:建立型模式、結構型模式、行為模式。
建立型模式抽象了例項化過程,它們幫助一個系統獨立於如何建立、組合和表示它的那些物件。一個類建立型模式使用繼承改變被例項化的類,而一個物件建立型模式將例項化委託給另一個物件。建立型模式有兩個不斷出現的主旋律。第一,它們都將關於該系統使用哪些具體的類的資訊封裝起來。第二,它們隱藏了這些類的例項是如何被建立和放在一起的。整個系統關於這些物件所知道的是由抽象類所定義的介面。因此,建立型模式在什麼被建立,誰建立它,它是怎樣被建立的,以及何時建立這些方面給予了很大的靈活性。它們允許用結構和功能差別很大的“產品”物件配置一個系統。配置可以是靜態的(即在編譯時指定),也可以是動態的(在執行時)。
結構型模式涉及到如何組合類和物件以獲得更大的結構。結構型類模式採用繼承機制來組合介面或實現。結構型物件模式不是對介面和實現進行組合,而是描述瞭如何對一些物件進行組合,從而實現新功能的一些方法。因為可以在執行時刻改變物件組合關係,所以物件組合方式具有更大的靈活性,而這種機制用靜態類組合是不可能實現的。
行為模式涉及到演算法和物件間職責的分配。行為模式不僅描述物件或類的模式,還描述它們之間的通訊模式。這些模式刻畫了在執行時難以跟蹤的複雜的控制流。它們將使用者的注意力從控制流轉移到物件間的聯絡方式上來。行為類模式使用繼承機制在類間分派行為。行為物件模式使用物件複合而不是繼承。一些行為物件模式描述了一組對等的物件怎樣相互協作以完成其中任一個物件都無法單獨完成的任務。
建立型模式包括:1、FactoryMethod(工廠方法模式);2、Abstract Factory(抽象工廠模式);3、Singleton(單例模式);4、Builder(建造者模式、生成器模式);5、Prototype(原型模式).
結構型模式包括:6、Bridge(橋接模式);7、Adapter(介面卡模式);8、Decorator(裝飾模式);9、Composite(組合模式);10、Flyweight(享元模式);11、Facade(外觀模式);12、Proxy(代理模式).
行為模式包括:13、TemplateMethod(模板方法模式);14、Strategy(策略模式);15、State(狀態模式);16、Observer(觀察者模式);17、Memento(備忘錄模式);18、Mediator(中介者模式);19、Command(命令模式);20、Visitor(訪問者模式);21、Chain of Responsibility(責任鏈模式);22、Iterator(迭代器模式);23、Interpreter(直譯器模式).
Factory Method:定義一個用於建立物件的介面,讓子類決定將哪一個類例項化。Factory Method使一個類的例項化延遲到其子類。
Abstract Factory:提供一個建立一系列相關或相互依賴物件的介面,而無需指定他們具體的類。
Singleton:保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。
Builder:將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。
Prototype:用原型例項指定建立物件的種類,並且通過拷貝這個原型來建立新的物件。
Bridge:將抽象部分與它的實現部分分離,使它們都可以獨立地變化。
Adapter:將一個類的介面轉換成客戶希望的另外一個介面。Adapter模式使得原本由於介面不相容而不能一起工作的那些類可以一起工作。
Decorator:動態地給一個物件新增一些額外的職責。就擴充套件功能而言, Decorator模式比生成子類方式更為靈活。
Composite:將物件組合成樹形結構以表示“部分-整體”的層次結構。Composite使得客戶對單個物件和複合物件的使用具有一致性。
Flyweight:運用共享技術有效地支援大量細粒度的物件。
Facade:為子系統中的一組介面提供一個一致的介面, Facade模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。
Proxy:為其他物件提供一個代理以控制對這個物件的訪問。
Template Method:定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。Template Method使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。
Strategy:定義一系列的演算法,把它們一個個封裝起來, 並且使它們可相互替換。本模式使得演算法的變化可獨立於使用它的客戶。
State:允許一個物件在其內部狀態改變時改變它的行為。物件看起來似乎修改了它所屬的類。
Observer:定義物件間的一種一對多的依賴關係,以便當一個物件的狀態發生改變時,所有依賴於它的物件都得到通知並自動重新整理。
Memento:在不破壞封裝性的前提下,捕獲一個物件的內部狀態,並在該物件之外儲存這個狀態。這樣以後就可將該物件恢復到儲存的狀態。
Mediator:用一箇中介物件來封裝一系列的物件互動。中介者使各物件不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的互動。
Command:將一個請求封裝為一個物件,從而使你可用不同的請求對客戶進行引數化;對請求排隊或記錄請求日誌,以及支援可取消的操作。
Visitor:表示一個作用於某物件結構中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用於這些元素的新操作。
Chain of Responsibility:為解除請求的傳送者和接收者之間耦合,而使多個物件都有機會處理這個請求。將這些物件連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個物件處理它。
Iterator:提供一種方法順序訪問一個聚合物件中各個元素, 而又不需暴露該物件的內部表示。
Interpreter:給定一個語言, 定義它的文法的一種表示,並定義一個直譯器, 該直譯器使用該表示來解釋語言中的句子。
Chain of Responsibility:(1)、意圖:使多個物件都有機會處理請求,從而避免請求的傳送者和接收者之間的耦合關係。將這些物件連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個物件處理它為支。
(2)、適用性:A、有多個的物件可以處理一個請求,哪個物件處理該請求執行時刻自動確定。B、你想在不明確指定接收者的情況下,向多個物件中的一個提交一個請求。C、可處理一個請求的物件集合應被動態指定。
(3)、優缺點:A、降低耦合度:該模式使得一個物件無需知道是其它哪一個物件處理其請求。物件僅需知道該請求會被”正確”地處理。接收者和傳送者都沒有對方的明確的資訊,且鏈中的物件不需知道鏈的結構。結果是,職責鏈可簡化物件的相互連線。它們僅需保持一個指向其後繼者的引用,而不需保持它所有的候選接收者的引用。B、增強了給物件指派職責(Responsibility)的靈活性:當在物件中分派職責時,職責鏈給你更多的靈活性。你可以通過在執行時刻對該鏈進行動態的增加或修改來增加或改變處理一個請求的那些職責。你可以將這種機制與靜態的特例化處理物件的繼承機制結合起來使用。C、不保證被接收:既然一個請求沒有明確的接收者,那麼就不能保證它一定會被處理------該請求可能一直到鏈的末端都得不到處理。一個請求也可能因為鏈沒有被正確配置而得不到處理。
(4)、相關模式:職責鏈常與Composite一起使用。這種情況下,一個構件的父構件可作為它的後繼。
(5)、Chain ofResponsibility模式中ConcreteHandler將自己的後繼物件(向下傳遞訊息的物件)記錄在自己的後繼表中,當一個請求到來時,ConcreteHandler會先檢檢視自己有沒有匹配的處理程式,如果有就自己處理,否則傳遞給它的後繼。Chain of Responsibility模式的最大的一個優點就是給系統降低了耦合性,請求的傳送者完全不必知道該請求會被哪個應答物件處理,極大地降低了系統的耦合性。
示例程式碼1:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
//請求
class Request
{
public:
string m_strContent;
int m_nNumber;
};
//管理者
class Manager
{
protected:
Manager* manager;
string name;
public:
Manager(string temp)
{
name = temp;
}
void SetSuccessor(Manager* temp)
{
manager = temp;
}
virtual void GetRequest(Request* request) = 0;
};
//經理
class CommonManager : public Manager
{
public:
CommonManager(string strTemp) : Manager(strTemp) {}
virtual void GetRequest(Request* request)
{
if (request->m_nNumber >= 0 && request->m_nNumber < 10)
cout<<name<<"處理了"<<request->m_nNumber<<"個請求"<<endl;
else
manager->GetRequest(request);
}
};
//總監
class MajorDomo : public Manager
{
public:
MajorDomo(string name) : Manager(name) {}
virtual void GetRequest(Request* request)
{
if (request->m_nNumber >= 10)
cout<<name<<"處理了"<<request->m_nNumber<<"個請求"<<endl;
}
};
//客戶端
int main()
{
Manager* common = new CommonManager("張經理");
Manager* major = new MajorDomo("李總監");
common->SetSuccessor(major);
Request* req = new Request();
req->m_nNumber = 33;
common->GetRequest(req);
req->m_nNumber = 3;
common->GetRequest(req);
/*result
李總監處理了33個請求
張經理處理了3個請求
*/
return 0;
}
示例程式碼2:
Handle.h:
#ifndef _HANDLE_H_
#define _HANDLE_H_
class Handle
{
public:
virtual ~Handle();
virtual void HandleRequest() = 0;
void SetSuccessor(Handle* succ);
Handle* GetSuccessor();
protected:
Handle();
Handle(Handle* succ);
private:
Handle* _succ;
};
class ConcreteHandleA : public Handle
{
public:
ConcreteHandleA();
~ConcreteHandleA();
ConcreteHandleA(Handle* succ);
void HandleRequest();
protected:
private:
};
class ConcreteHandleB : public Handle
{
public:
ConcreteHandleB();
~ConcreteHandleB();
ConcreteHandleB(Handle* succ);
void HandleRequest();
protected:
private:
};
#endif//~_HANDLE_H_
Handle.cpp:
#include "Handle.h"
#include <iostream>
using namespace std;
Handle::Handle()
{
_succ = 0;
}
Handle::~Handle()
{
delete _succ;
}
Handle::Handle(Handle* succ)
{
this->_succ = succ;
}
void Handle::SetSuccessor(Handle* succ)
{
_succ = succ;
}
Handle* Handle::GetSuccessor()
{
return _succ;
}
void Handle::HandleRequest()
{
}
ConcreteHandleA::ConcreteHandleA()
{
}
ConcreteHandleA::ConcreteHandleA(Handle* succ) : Handle(succ)
{
}
ConcreteHandleA::~ConcreteHandleA()
{
}
void ConcreteHandleA::HandleRequest()
{
if (this->GetSuccessor() != 0) {
cout<<"ConcreteHandleA 我把處理權給後繼節點 ..."<<endl;
this->GetSuccessor()->HandleRequest();
} else
cout<<"ConcreteHandleA 沒有後繼了, 我必須自己處理 ..."<<endl;
}
ConcreteHandleB::ConcreteHandleB()
{
}
ConcreteHandleB::ConcreteHandleB(Handle* succ) : Handle(succ)
{
}
ConcreteHandleB::~ConcreteHandleB()
{
}
void ConcreteHandleB::HandleRequest()
{
if (this->GetSuccessor() != 0) {
cout<<"ConcreteHandleB 我把處理權給後繼節點 ..."<<endl;
this->GetSuccessor()->HandleRequest();
} else
cout<<"ConcreteHandleB 沒有後繼了,我必須自己處理 ..."<<endl;
}
main.cpp:
#include "Handle.h"
#include <iostream>
using namespace std;
int main()
{
Handle* h1 = new ConcreteHandleA();
Handle* h2 = new ConcreteHandleB();
h1->SetSuccessor(h2);
h1->HandleRequest();
/*result
ConcreteHandleA 我把處理權給後繼節點 ...
ConcreteHandleB 沒有後繼了,我必須自己處理 ...
*/
return 0;
}
職責鏈模式結構圖:
參考文獻:
1、《大話設計模式C++》
2、《設計模式精解----GoF23種設計模式解析》
3、《設計模式----可複用面向物件軟體的基礎》