策略模式的定義:
策略模式是指定義一系列的算法,把它們一個個封裝起來,並且使它們可相互替換。本模式使得算法可獨立於使用它的客戶而變化。
優點: 1、算法可以自由切換。 2、避免使用多重條件判斷。 3、擴展性良好。
缺點: 1、策略類會增多。 2、所有策略類都需要對外暴露。
類圖如下:
Strategy: 抽象策略類,定義抽象的函數算法讓繼承的子類實現。
ConcreteStrategy:封裝了繼續相關的算法和行為,即函數的具體功能的實現。
Context:持有一個策略類的引用,最終給客戶端調用。
我認為策略模式的重點在於context類的定義,這也是策略模式與模板模式最大的不同,即通過對策略基類Strategy的組合出的類context,根據子類的不同,靈活地通過類context中的多態指針調用來實現一系列子類算法,也叫根據不同策略執行不同的行為。策略由外部環境決定。
總結起來就是Context 指向 Strategy (由指針實現);Context 通過 Strategy 接口,調用一系列算法;ConcreteStrategy 實現了一系列具體的算法。
下面舉一個例子來說明策略模式的好處:
假如一個跨國公司A在多個國家有分公司,且在不同國家的經營模式根據國家國情會有所不同,而且分公司負責人也不同,要求編寫程序實現這一情況的描述。首先容易想到的是定義一個基類,然后針對不同的分公司用switch語句進行選擇來編寫。代碼如下:
1
#include <iostream>
using namespace std;
class Company
{
private:
string name;
int type;
public:
Company(string n,int t)
{
name=n;
type=t;
}
void printcompany()
{
switch(type)
{
case 1:
cout<<"負責人"<<name<<endl;
China();
break;
case 2:
cout<<"負責人"<<name<<endl;
America();
break;
case 3:
cout<<"負責人"<<name<<endl;
France();
break;
}
}
void China()
{
cout<<"中國分公司:經營模式1的具體實現..."<<endl;
}
void America()
{
cout<<"美國分公司:經營模式2的具體實現..."<<endl;
}
void France()
{
cout<<"法國分公司:經營模式3的實現..."<<endl;
}
};
int main()
{
Company a1("張三",1);
Company a2("李四",2);
Company a3("王五",3);
a1.printcompany();
cout<<"================================================="<<endl;
a2.printcompany();
cout<<"================================================="<<endl;
a3.printcompany();
}
然而這個程序只是最簡單的做法,其擴展性並不好,例如要在印度一個新分公司,需要在類添加相關公司經營模式函數,也要在switch添加相關公司內容,如果某個分公司的經營模式要改變,也要通過去類中尋找相應的函數去修改,但如果分公司多了,類就會變得很臃腫且不方便查找修改。如果我們采用策略模式,把函數定義寫在抽象基類中,把每個分公司寫成一個繼承子類,由不同的算法實現不同經營模式,然后再寫一個封裝的context類來實現客戶端調用,這樣就可以一目了然了,建立分公司和修改信息就只需要對子類進行操作,基類並不需要任何修改,而且通過contex類提供的接口可以很方便的選擇展示不同公司的情況,代碼如下:
#include <iostream> using namespace std; class Company { public: string name; virtual void Management()=0; }; class Company1:public Company { public: Company1(string n) {
name=n; } void printcompany() { cout<<"負責人"<<name<<endl; } virtual void Management() { cout<<"中國分公司:經營模式1的具體實現..."<<endl; } }; class Company2:public Company { public: Company2(string n) { name=n; } void printcompany() { cout<<"負責人"<<name<<endl; } virtual void Management() { cout<<"美國分公司:經營模式2的具體實現..."<<endl; } }; class Company3:public Company { public: Company3(string n) { name=n; } void printcompany() { cout<<"負責人"<<name<<endl; } virtual void Management() { cout<<"法國分公司:經營模式3的實現..."<<endl; } }; class Context { public: Company *com; Context(Company *c) { com=c; } void printcompany() { com->Management(); } }; int main() { Company *china=new Company1("張三"); Company *america=new Company2("張三"); Company *france=new Company3("張三"); Context a1(china); Context a2(america); Context a3(france); a1.printcompany(); cout<<"================================================="<<endl; a2.printcompany(); cout<<"================================================="<<endl; a3.printcompany(); }
從設計模式的角度來說,這種模式隔離變化,編程到接口,有新公司加入,只要寫一個子類就可以,不需要改變其他類的代碼,所以其他的類都是穩定的,這就體現了我們策略模式的設計原則和目的。