轉載自:
http://patmusing.blog.163.com/blog/static/1358349602010150224904/也稱為Policy模式。
定義一系列算法,把他們一個個封裝起來,并且使他們可以相互替換。該模式使得算法可以獨立于使用它的客戶而變化。
“Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.”- GoF
在軟件構建過程中,某些對象使用的算法可能多種多樣,經常改變,如果將這些算法都編碼到某個對象中,將會使該對象變得異常復雜;而且有時候支持不使用的算法也是一個性能負擔。Strategy設計模式就是在運行時根據需要透明地更改對象的算法,將算法和對象本身解耦。
我們在編程中,經常碰到這樣的情況:用不同的辦法去做同一件事情,比如,
1. 將文件保存為不同的格式;
2. 用不同的壓縮算法壓縮一個文本文件;
3. 用不同的壓縮算法壓縮視頻文件
4. 將同樣的數據,用不同的圖形顯示出來:折線圖、柱狀圖或者餅圖;
5. 將用某種語言寫的一個句子,翻譯成為幾種其他的語言。
客戶程序告訴驅動模塊(不妨稱為Context),它將使用哪個算法(即所謂的strategy或policy),并請求Context執行該算法。
Strategy模式UML類圖:
v
角色:
Strategy:
- 給所有支持的算法聲明一個通用接口,Context使用該接口調用由ConcreteStrategy定義的算法。
ConcreteStrategy:
- 按照Strategy給出的接口實現具體的算法。
Context
- 包含一個Strategy的引用;
- 可以由ConcreteStrategy對象對其進行配置。
業務示例:
將阿拉伯數字“520”分別翻譯成中文、英語和俄語。
下面是具體C++代碼:
// Strategy.h
#include <iostream>
#include <string>
#include <memory>
using namespace std;
// Strategy抽象類,用做借口
class Strategy
{
public:
virtual string substitute(string str) = 0;
public:
virtual ~Strategy()
{
cout << "in the destructor of Strategy..." << endl;
}
};
// 中文Strategy
class ChineseStrategy : public Strategy
{
public:
string substitute(string str)
{
size_t index = str.find("520");
string tempstr = str.replace(index, 3, "我愛你");
return tempstr;
}
public:
~ChineseStrategy()
{
cout << "in the destructor of ChineseStrategy..." << endl;
}
};
// 英語Strategy
class EnglishStrategy : public Strategy
{
public:
string substitute(string str)
{
size_t index = str.find("520");
string tempstr = str.replace(index, 3, "I love you");
return tempstr;
}
public:
~EnglishStrategy()
{
cout << "in the destructor of EnglishStrategy..." << endl;
}
};
// 俄語Strategy
class RussianStrategy : public Strategy
{
public:
string substitute(string str)
{
size_t index = str.find("520");
string tempstr = str.replace(index, 3, "Я люблю тебя");
return tempstr;
}
public:
~RussianStrategy()
{
cout << "in the destructor of RussiaStrategy..." << endl;
}
};
// Context類
class Translator
{
private:
auto_ptr<Strategy> strategy;
public:
~Translator()
{
cout << "in the destructor of Translator..." << endl;
}
public:
void set_strategy(auto_ptr<Strategy> strategy)
{
this->strategy = strategy;
}
string translate(string str)
{
if(0 == strategy.get()) return "";
return strategy->substitute(str);
}
};
// Strategy.cpp
#include "Strategy.h"
int main(int argc, char** argv)
{
string str("321520");
Translator* translator = new Translator;
// 未指定strategy時
cout << "No strategy: " << translator->translate(str) << endl;
cout << "--------------------------" << endl;
// 翻譯成中文
auto_ptr<Strategy> s1(new ChineseStrategy());
translator->set_strategy(s1);
cout << "Chinese strategy: " << translator->translate(str) << endl;
cout << "--------------------------" << endl;
// 翻譯成英語
auto_ptr<Strategy> s2(new EnglishStrategy());
translator->set_strategy(s2);
cout << "English strategy: " << translator->translate(str) << endl;
cout << "--------------------------" << endl;
// 翻譯成俄語
auto_ptr<Strategy> s3(new RussianStrategy());
translator->set_strategy(s3);
cout << "Russian strategy: " << translator->translate(str) << endl;
cout << "--------------------------" << endl;
delete translator;
return 0;
}
運行結果:
No strategy:
--------------------------
Chinese strategy: 321我愛你
--------------------------
in the destructor of ChineseStrategy...
in the destructor of Strategy...
English strategy: 321I love you
--------------------------
in the destructor of EnglishStrategy...
in the destructor of Strategy...
Russian strategy: 321Я люблю тебя
--------------------------
in the destructor of Translator...
in the destructor of RussiaStrategy...
in the destructor of Strategy...
結果符合預期。
1. 從上面程序可以很容易看出,可以在運行時改變translator對象的行為;
2. 算法如果改變了,客戶端程序不需要做任何改動,比如在EnglishStrategy的實現中將“520”翻譯成“Five hundred and twenty”,客戶端代碼無需任何改變;
3. 當需要增加新的算法時,比如要將“520”翻譯成日語的“わたし愛してるあなた”,只需要增加一個具體的Strategy類,比如JapaneseStrategy類,并重寫Strategy中聲明的純虛函數即可。這完全符合OCP。
上述代碼的UML類圖:
Strategy模式和State粗看起來非常相似,但他們的意圖完全不同。他們主要的區別在于:
1. Strategy一次只能選擇一個strategy(即算法),而State模式中,不同的狀態有可能同時被激活;
2. Strategy封裝的是算法,State封裝的是狀態;
3. Strategy所封裝的算法(每個算法對應一個類),所做的事情相差無幾,而State所封裝的狀態(每個狀態對應一個類),往往頗不相同;
4. State模式中的狀態遷移的概念,在Strategy中根本不存在。