概念:
策略模式定義了一系列的算法,分別封裝起來,讓它們之間可以相互替換。此模式讓算法的變化,不會影響到使用算法的客戶。策略,實質上指的是算法。
例子:
一個鮮活簡單的例子總能讓人輕鬆地理解晦澀的概念。我們來看看一個關於汽車價格的策略模式。
我們知道,汽車的品牌和質量,決定了它的價格。就像寶馬(BMW),法拉利(Ferrali)和奔馳(Benz)三輛汽車,它們的價格肯定是不一樣的。那如果想要知道它的價格的話,可以詢問銷售人員等等。但是在計算機裏,我們可不能直接問銷售人員啊!
對於它們來說,雖然各自價格不同,是不同的算法,但是獲取價格卻是一種公共操作(策略模式要求的就是要封裝變化的算法)。於是,可以創建一個抽象父類汽車類(Car),聲明一個獲取價格virtual GetPrice函數的接口。然後創建三個子類:BMW,Ferrali和Benz,分別繼承於Car。通過繼承關係,每個子類可以改寫父類的GetPrice函數,然後在客戶端中通過調用不同的汽車子類算法來獲取子類汽車價格。
總結一下:
1、我們把父類Car當成是抽象策略類,提供了一個獲取價格的GetPrice接口;
2、每種包含獲取價格GetPrice的汽車類爲具體策略類(每種牌子的車價格不一致,導致不同計算算法),要重寫父類Car的GetPrice函數;
3、建立一個環境上下文類PriceContext,維護一個對父類Car對象(指針對象才能實現多態)的引用,最後給客戶端調用具體的策略類對象。
UML圖:
代碼:
#include <iostream>
using namespace std;
class Car
{
public:
float m_fPrice;
public:
virtual float GetPrice()
{
return m_fPrice*1;
}
};
class BMW:public Car
{
public:
float GetPrice()
{
return m_fPrice*3;
}
};
class Ferrali:public Car
{
public:
float GetPrice()
{
return m_fPrice*11;
}
};
class Benz:public Car
{
public:
float GetPrice()
{
return m_fPrice*6;
}
};
class PriceContext
{
public:
int m_iFlag;
private:
Car* m_cCar;
public:
PriceContext(Car* cCar):m_cCar(cCar)
{
//this->m_cCar = cCar;
}
float GetPriceContext()
{
m_cCar->m_fPrice = 10000;
return(m_cCar->GetPrice());
}
};
int main()
{
float fPrice=0.0;
int iTag=0;
cout<<"----策略模式開始----"<<endl;
cout<<"BMW:1,Ferrali:2,Benz:3"<<endl;
cout<<"請輸入您想要查詢的汽車價格:";
cin>>iTag;
PriceContext* priceContext;
switch (iTag)
{
case 1:
priceContext = new PriceContext(new BMW);
break;
case 2:
priceContext = new PriceContext(new Ferrali);
break;
case 3:
priceContext = new PriceContext(new Benz);
break;
default:
priceContext = new PriceContext(new Car);
break;
}
fPrice = priceContext->GetPriceContext();
delete priceContext;
priceContext = NULL;
cout<<"價格爲:"<<fPrice<<endl;
cout<<"----策略模式結束----"<<endl;
return 1;
}
策略模式和簡單工廠模式相結合:
簡單工廠模式中,對象的動態創建判斷放在了工廠類中。而基本的策略模式客戶端還是要進行算法判斷和對象創建。因此可模仿簡單工廠,把算法的判斷移到環境上下文類中,儘量減少客戶端職責,降低耦合性。其中相對簡單工廠模式來說,客戶端中連基類都不出現,更加地隱藏算法的具體實現細節。
代碼:
class PriceContext
{
public:
int m_iFlag;
private:
Car* m_cCar;
public:
PriceContext(int iFlag) //構造中不再穿對象,傳標識
{
switch (iFlag)
{
case 1:
m_cCar = new BMW;
break;
case 2:
m_cCar = new Ferrali;
break;
case 3:
m_cCar = new Benz;
break;
default:
m_cCar = new Car;
break;
}
}
float GetPriceContext()
{
m_cCar->m_fPrice = 10000;
return(m_cCar->GetPrice());
}
};
int main()
{
float fPrice=0.0;
int iTag=0;
cout<<"----策略模式開始----"<<endl;
cout<<"BMW:1,Ferrali:2,Benz:3"<<endl;
cout<<"請輸入您想要查詢的汽車價格:";
cin>>iTag;
PriceContext* priceContext = new PriceContext(iTag);
fPrice = priceContext->GetPriceContext();
delete priceContext;
priceContext = NULL;
cout<<"價格爲:"<<fPrice<<endl;
cout<<"----策略模式結束----"<<endl;
return 1;
}
總結:
1、策略模式定義了一系列的算法,從概念上看,所有算法完成的都是相同的操作,只是表現行爲不同。通過相同的方式調用所有的算法(使用多態),減少了算法類與使用算法類之間的耦合;
2、對客戶隱藏具體策略(算法)的實現細節,彼此完全獨立;
3、策略模式簡化了單元測試,每個算法都有自己的類,可以通過自己的接口單獨測試;
4、客戶端必須知道所有的策略類,並自行決定使用哪一個策略類。這就意味着客戶端必須理解這些算法的區別,以便適時選擇恰當的算法類。換言之,策略模式只適用於客戶端知道所有的算法或行爲的情況。