設計模式 c++版(13)——策略模式
阿新 • • 發佈:2018-12-12
定義: 定義一組演算法,將每個演算法都封裝起來,並且使他們之間可以互換
示例一:策略模式(通用版)
1. 類圖18-3
2. 類圖說明
策略模式使用的就是面向物件的繼承和多型機制
- Context 封裝角色。也叫上下文角色,起承上啟下的封裝作用,遮蔽高層模組對策略、演算法的直接訪問,封裝可能存在的變化。
- Strategy 抽象策略角色。策略、演算法家族的抽象,通常為藉口,定義每個策略或演算法必須具有的方法和屬性。
- ConcreteStrategy 具體策略角色。實現抽象策略中的操作,該類含有具體的演算法。
3. 程式碼清單18-3
//////////////////////// ********** 1. 策略模式(通用版),程式碼清單18-3:***************// //抽象的策略角色 class Strategy { public: virtual void operate() = 0; }; //具體策略角色 class ConcreteStrategy1: public Strategy { public: virtual void operate(){qDebug() << "ConcreteStrategy1";} }; //吳國太開綠燈 class ConcreteStrategy2: public Strategy { public: virtual void operate(){qDebug() << "ConcreteStrategy2";} }; //封裝角色 class Context { public: Context(Strategy* strategy) { this->m_strategy = strategy; } void operate() { this->m_strategy->operate(); } private: Strategy *m_strategy; }; //使用計謀 int main() { Strategy *gy1 = new ConcreteStrategy1(); Strategy *gy2 = new ConcreteStrategy2(); Context *context = new Context(gy1); context->operate(); context = new Context(gy2); context->operate(); return 0; }
4. 程式碼分析
策略模式就是採用了面向物件的繼承和多型機制。在真實的業務環境中,需要看清楚哪個介面是抽象策略介面,哪些是和策略模式沒有任何關係的。
示例二:三國策略
1. 類圖18-1
2. 類圖結構
- IStrategy :策略類總稱
- BackDoor:喬國老開後門
- GivenGreenLight:吳國太開綠燈
- BlockEnemy:孫夫人斷後
3.增加錦囊和執行人,類圖18-2
4.程式碼清單
////////////////////// ********** 2. 三國策略,程式碼清單18-2:***************// //妙計介面 class IStrategy { public: virtual void operate() = 0; }; //喬國老開後門 class BackDoor: public IStrategy { public: virtual void operate(){qDebug() << "BackDoor";} }; //吳國太開綠燈 class GivenGreenLight: public IStrategy { public: virtual void operate(){qDebug() << "GivenGreenLight";} }; //孫夫人斷後 class BlockEnemy: public IStrategy { public: virtual void operate(){qDebug() << "BlockEnemy";} }; //錦囊 class Context { public: Context(IStrategy* strategy) { this->m_strategy = strategy; } void operate() { this->m_strategy->operate(); } private: IStrategy *m_strategy; }; //使用計謀 int main() { IStrategy *backDoor = new BackDoor(); IStrategy *greenLight = new GivenGreenLight(); IStrategy *block = new BlockEnemy(); Context *context = new Context(backDoor); context->operate(); context = new Context(greenLight); context->operate(); context = new Context(block); context->operate(); return 0; }
三、建造者模式的應用
1. 優點
- 演算法可以自由切換。這是策略模式本身定義的,只要實現抽象策略,它就成為策略家族的一個成員,通過封裝角色對其進行封裝,保證對外提供“可自由切換”的策略。
- 避免使用多重條件判斷。多重條件語句不易維護,而且出錯的概率大大增強。使用策略模式後,可以由其他模組決定採用何種策略,策略家族對外提供的訪問介面就是封裝類,簡化了操作,同時避免了條件語句判斷。
- 擴充套件性良好。在現有的系統中增加一個策略很容易,只要實現介面就可以了,其他不用修改,類似於一個可反覆拆卸的外掛。
2. 缺點
- 策略類數量增多。每一個策略都是一個類,複用的可能性很小,類數量增多。
- 所有的策略類都需要對外暴露。上層模組必須知道有哪些策略,然後才能決定使用哪一個策略,這與迪米特法則相違背,這一缺點可以使用其他模式來修補,如工廠方法模式、代理模式或享元模式。
3. 使用場景:
- 多個類只有在演算法或行為上稍有不同的場景。
- 演算法需要自由切換的場景。如演算法的選擇由使用者決定。
- 需要遮蔽演算法規則的場景。如太多的演算法只要知道一個名字,傳遞相關的數字進來,反饋一個運算結果就可以。
4. 注意事項:
如果系統中的一個策略家族的具體策略數量超過4個,則需要考慮使用混合模式,解決策略類膨脹和對外暴露的問題,否則日後的系統維護就會很麻煩。
四、策略模式的擴充套件
1. 需求說明
輸入3個引數,進行加減運算,引數中兩個是int,一個是QString,只有“+”、“-”兩個符號可以選擇,不考慮校驗
示例三:算數加減法(方案一)
2. 程式碼清單18-3
//////////////////////// ********** 3. 算數加減法(方案一),程式碼清單18-3:***************//
class Calculator
{
public:
int exec(int a, int b, QString symbol)
{
int result = 0;
if (symbol == this->m_add)
{
result = this->add(a, b);
}
else if (symbol == this->m_sub)
{
result = this->sub(a, b);
}
return result;
}
private:
int add(int a, int b){return a + b;}
int sub(int a, int b){return a - b;}
private:
static QString m_add;
static QString m_sub;
};
QString Calculator::m_add = "+";
QString Calculator::m_sub = "-";
int main()
{
int a = 10;
int b = 20;
Calculator cal;
qDebug() << cal.exec(a, b, "+");
return 0;
}
示例四:算數加減法(方案二)
2. 程式碼清單18-3,( 簡化Calculator )
//////////////////////// ********** 4. 算數加減法(方案二),程式碼清單18-4:***************//
class Calculator
{
public:
int exec(int a, int b, QString symbol)
{
return (symbol == m_add)? a+b:a-b;
}
private:
int add(int a, int b){return a + b;}
int sub(int a, int b){return a - b;}
private:
static QString m_add;
static QString m_sub;
};
QString Calculator::m_add = "+";
QString Calculator::m_sub = "-";
int main()
{
int a = 10;
int b = 20;
Calculator cal;
qDebug() << cal.exec(a, b, "+");
return 0;
}
示例五:算數加減法(方案三)
2. 程式碼清單18-3,( 引入策略模式 )
////////////// ********** 5. 算數加減法(方案三:策略模式),程式碼清單18-5:***************//
class Calculator
{
public:
virtual int exec(int a, int b) = 0;
};
class Add:public Calculator
{
public:
virtual int exec(int a, int b)
{
return a + b;
}
};
class Sub:public Calculator
{
public:
virtual int exec(int a, int b)
{
return a - b;
}
};
class Context
{
public:
Context(Calculator *cal)
{
this->m_cal = cal;
}
int exec(int a, int b)
{
return this->m_cal->exec(a, b);
}
private:
Calculator *m_cal;
};
int main()
{
int a = 10;
int b = 20;
Calculator *cal = new Add();
Context context(cal);
qDebug() << context.exec(a, b);
return 0;
}
六、最佳實踐
策略模式是一個非常簡單的模式。他在專案中使用的非常多,但單獨使用的地方比較少,因為有致命缺陷:所有的策略都需要暴露出去,這樣才方便客戶端決定使用哪一個策略。
參考文獻《秦小波. 設計模式之禪》(第2版) (華章原創精品) 機械工業出版社