責任鏈模式與策略模式
責任鏈模式
Chain of Responsibility(CoR)模式也叫職責鏈模式或者職責連鎖模式,是行為模式之一,該模式構造一系列分別擔當不同的職責的類的物件來共同完成一個任務,這些類的物件之間像鏈條一樣緊密相連,所以被稱作職責鏈模式。
例1:比如客戶Client要完成一個任務,這個任務包括a,b,c,d四個部分。
首先客戶Client把任務交給A,A完成a部分之後,把任務交給B,B完成b部分,…,直到D完成d部分。
例2:比如政府部分的某項工作,縣政府先完成自己能處理的部分,不能處理的部分交給省政府,省政府再完成自己職責範圍內的部分,不能處理的部分交給中央政府,中央政府最後完成該項工作。
例3:軟體視窗的訊息傳播。
適用於:
鏈條式處理事情。工作流程化、訊息處理流程化、事物流程化;
角色及職責
Handler
處理類的抽象父類–裡面有一個自己型別的指標做成員變數,類似於連結串列。
concreteHandler
具體的處理類。
優缺點
優點:
責任的分擔。每個類只需要處理自己該處理的工作(不該處理的傳遞給下一個物件完成),明確各類的責任範圍,符合類的最小封裝原則。各司其職!
可以根據需要自由組合工作流程。如工作流程發生變化,可以通過重新分配物件鏈便可適應新的工作流程。流程可以自由組合!
類與類之間可以以鬆耦合的形式加以組織。低耦合!
缺點:
因為處理時以鏈的形式在物件間傳遞訊息,根據實現方式不同,有可能會影響處理的速度。
案例
/*通過使用者的狀態改變物件當前的行為*/
#include <iostream>
using namespace std;
/*抽象處理類--提供設定物件鏈的介面,客戶端根據物件鏈將任務按照指定流程完成*/
class CarMake
{
public:
CarMake()
{
m_make = NULL;
}
virtual void MakeCar() = 0;
void setCarMake(CarMake *make)//設定物件鏈--實際上就是指定當前物件任務完成以後要執行任務的下一個物件
{
m_make = make;
}
protected :
CarMake *m_make;//指向下一個要執行任務的具體物件
};
/*具體處理類--繼承自抽象處理類*/
class HeadMake:public CarMake
{
public:
virtual void MakeCar()
{
cout<<"make head"<<endl;//執行自己的任務
if(m_make != NULL)
m_make->MakeCar();//自己的任務處理完畢以後,自動呼叫下一個具體處理物件的任務
}
};
/*具體處理類--繼承自抽象處理類*/
class BodyMake:public CarMake
{
public:
virtual void MakeCar()
{
cout<<"make body"<<endl;
if(m_make != NULL)
m_make->MakeCar();
}
};
class TailMake:public CarMake
{
public:
virtual void MakeCar()
{
cout<<"make tail"<<endl;
if(m_make != NULL)
m_make->MakeCar();
}
};
int main()
{
/*建立具體的處理物件*/
CarMake * head = new HeadMake;
CarMake * body = new BodyMake;
CarMake * tail = new TailMake;
/*設定物件處理鏈*/
head->setCarMake(body);
body->setCarMake(tail);
tail->setCarMake(NULL);
/*從連結串列頭開始鏈式執行任務*/
head->MakeCar();
delete head ;
delete body ;
delete tail ;
return 0;
}
策略模式
Strategy模式也叫策略模式是行為模式之一,它對一系列的演算法加以封裝,為所有演算法定義一個抽象的演算法介面,並通過繼承該抽象演算法介面對所有的演算法加以封裝和實現,具體的演算法選擇交由客戶端決定(策略)。Strategy模式主要用來平滑地處理演算法的切換 。
在巨集觀上對演算法進行替換!這一點與模板模式不一樣!模板模式是在抽象模板類裡面有一個模板函式,裡面固定了巨集觀上的演算法,只是在具體類裡面重寫了每一步驟的虛擬函式!這種模式的巨集觀演算法就一個,比較單一!
而策略模式相當於重寫模板模式的模板函式(巨集觀演算法函式),每一個子類(具體策略類)對應一種具體的演算法,基類提供了一個統一的抽象演算法介面!
最終抽象的策略類又供上下文環境(策略的容器)使用!客戶端通過呼叫上下文環境類的物件,對演算法進行選擇和替換!
角色和職責
Strategy:
策略(演算法)抽象。
ConcreteStrategy
各種策略(演算法)的具體實現。
Context
策略的外部封裝類,或者說策略的容器類。根據不同策略執行不同的行為。策略由外部環境決定。
適用於:
準備一組演算法,並將每一個演算法封裝起來,使得它們可以互換。
優缺點
優點:
策略模式提供了管理相關的演算法族的辦法。策略類的等級結構定義了一個演算法或行為族。恰當使用繼承可以把公共的程式碼移到父類裡面,從而避免重複的程式碼。
策略模式提供了可以替換繼承關係的辦法。繼承可以處理多種演算法或行為。如果不是用策略模式,那麼使用演算法或行為的環境類就可能會有一些子類,每一個子類提供一個不同的演算法或行為。但是,這樣一來演算法或行為的使用者就和演算法或行為本身混在一起。決定使用哪一種演算法或採取哪一種行為的邏輯就和演算法或行為的邏輯混合在一起,從而不可能再獨立演化。繼承使得動態改變演算法或行為變得不可能。
使用策略模式可以避免使用多重條件轉移語句。多重轉移語句不易維護,它把採取哪一種演算法或採取哪一種行為的邏輯與演算法或行為的邏輯混合在一起,統統列在一個多重轉移語句裡面,比使用繼承的辦法還要原始和落後。
缺點:
客戶端必須知道所有的具體策略類,並自行決定使用哪一個策略類。這就意味著客戶端必須理解這些演算法的區別,以便適時選擇恰當的演算法類。換言之,策略模式只適用於客戶端知道所有的演算法或行為的情況。
策略模式造成很多的策略類。有時候可以通過把依賴於環境的狀態儲存到客戶端裡面,而將策略類設計成可共享的,這樣策略類例項可以被不同客戶端使用。換言之,可以使用享元模式來減少物件的數量。
案例
/*將具體演算法封裝成一個類
*所有具體演算法類繼承自同一個基類
* 基類作為上下文環境類的成員變數(關聯)和函式引數(依賴)
* 客戶端通過上下文環境類例項對演算法進行選擇和呼叫
* 客戶端要知道每一種具體演算法類
*/
#include <iostream>
using namespace std;
/*抽象策略類*/
class Strategy
{
public:
virtual void crypt() = 0;//巨集觀演算法介面
};
/*具體策略類*/
class AES: public Strategy
{
public:
virtual void crypt()
{
cout<< "AES"<<endl;//實現了巨集觀演算法
}
};
/*具體策略類*/
class DES: public Strategy
{
public:
virtual void crypt()
{
cout<< "DES"<<endl;//實現了巨集觀演算法
}
};
/*上下文環境類*/
class Context
{
public:
void setStrategy(Strategy *strategy)//設定策略類--由客戶端呼叫
{
m_strategy = strategy;
}
void doAction()//客戶端通過該介面--抽象演算法介面(封裝了具體的巨集觀演算法)--呼叫具體演算法
{
m_strategy->crypt();
}
private:
Strategy * m_strategy;
};
/*測試案例*/
int main()
{
/*策略類例項--供上下文環境使用*/
Strategy * strategy = NULL;
/*上下文類例項--供客戶端使用--呼叫抽象演算法doAction*/
Context * context = NULL;
/*例項化*/
strategy = new AES;
context = new Context;
/*設定演算法*/
context->setStrategy(strategy);
/*呼叫演算法*/
context->doAction();
/*記憶體回收*/
delete strategy ;
delete context ;
/*例項化*/
strategy = new DES;
context = new Context;
/*設定演算法*/
context->setStrategy(strategy);
/*呼叫演算法*/
context->doAction();
/*記憶體回收*/
delete strategy ;
delete context ;
return 0;
}