動機:在軟件構建的過程當中,某些對象使用的算法可能多種多樣,常常改變,若是將這些算法都編碼到對象中,將會使對象變得異常複雜,增長與改變現有算法可能帶來嚴重的邏輯問題;並且有時候支持不使用的算法也是一個性能上的負擔(具體上體如今代碼太長會使得其在保存的位置出現問題),所以將對象與算法解耦,避免上述問題纔是本算法動機。
意圖:定義一系列的算法,把它們一個個封裝起來,而且使它們能夠相互替換。本模式使得算法可獨立於使用它的客戶而改變。ios
示例代碼:算法
#ifndef STRATEGY #define STRATEGY #include<iostream> using std::cout; using std::ends; using std::endl; class Tax_cal { public: Tax_cal(); ~Tax_cal(); virtual double get_tax(double source_money)const = 0; private: }; Tax_cal::Tax_cal() {} Tax_cal::~Tax_cal() {} class chinese_tax:public Tax_cal { public: chinese_tax(); ~chinese_tax(); double get_tax(double source_money) const { return source_money * 5.6/100 ; } }; chinese_tax::chinese_tax() {} chinese_tax::~chinese_tax() {} class Japanese:public Tax_cal { public: Japanese(); ~Japanese(); double get_tax(double source_money)const { return source_money * 17 / 100; } private: }; Japanese::Japanese() { } Japanese::~Japanese() { } class bank_calcu { public: bank_calcu(double); ~bank_calcu() {}; void Calculate(const Tax_cal*); private: double money; }; bank_calcu::bank_calcu(double money) :money(money) {}; void bank_calcu::Calculate(const Tax_cal* tax_demo) { cout << tax_demo->get_tax(money) << endl; } #endif // !STRATEGY
咱們定義了一個客戶端的類bank_calcu用於計算不一樣地方的稅率,在成員函數Calculate()中計算稅率,可是不一樣的地方有不一樣的稅率,譬如說代碼中的中國與日本(固然數據是瞎編的),傳統的方法是在Calculate()內部寫上一個if-else或者switch語句來進行區別,可是依舊存在問題:
一、用不到的代碼塊就應該被去除,不然影響執行效率;
二、違反了開閉原則(對增長開放,對修改封閉);
三、容易出錯,如今的邏輯尚未那麼複雜,判斷邏輯十分複雜的話,修改會形成嚴重的邏輯問題。
稅率計算的過程咱們定義一個抽象類Tax_cal,使用其進行稅率的具體計算,不一樣的計算規則在其子類中進行具體實現,經過這種方式可以有效地實現稅率計算的功能。
運行代碼爲:函數
#include"strategy.h" int main() { bank_calcu bc(16000); bc.Calculate(new chinese_tax()); bc.Calculate(new Japanese()); std::cin.get(); }
結果爲
Strategy模式的優勢主要爲:
一、相關算法系列
Strategy類層次爲bank_calcu 定義了一系列可供重用的算法與行爲。繼承有助於析取出這些算法中的公共功能。
二、一個代替繼承的方法
在代碼中咱們還能夠這樣設計,也就是給bank_calcu 設計派生類,每一個派生類支持獨有的算法,可是這樣的派生類不只存在大量的代碼重複,也就是未作到有效地複用,也會帶來難以拓展與難以維護的問題。將算法封裝在Strategy類中有利於理解與擴展。
三、消除了一些條件語句
Strategy提供了用條件語句選擇所需的行爲之外的另外一種選擇。
四、實現了選擇
Strategy 模式能夠提供相同的行爲的不一樣實現。
其主要缺點爲:
一、客戶必需要了解不一樣的Strategy
也就是說既然須要選擇合適的Strategy就須要客戶瞭解不一樣的Strategy的區別在哪,這可能須要將策略的具體實現過程暴露給了用戶。
二、Strategy與bank_calcu 的通訊開銷
在本代碼範例中Strategy的具體實現共享一個接口,可是實際狀況下因爲某些差別,入口參數並非全部的派生類成員函數都須要的,可是這種方式可以下降二者之間的耦合度;另外一種方法是將bank_calcu的引用做爲參數傳入,或者直接在Strategy存儲一個bank_calcu引用,這樣會形成必定程度的高耦合。
三、增長了對象的個數
Strategy雖然說消除了bank_calcu 中的代碼臃腫與難以擴展的問題,可是其代價就是須要大量的類。
四、一些小的tip:
在進行Strategy的選擇的時候須要傳入一個具體Strategy指針,可是還有其餘的辦法,也就是經過模板,修改後的bank_calcu 能夠經過模板選擇:性能
template<class Tax_cal> class bank_calcu { public: bank_calcu(double); ~bank_calcu(); void Calculate(); private: double money; Tax_cal* tax_type;//保存一個Abstrategy指針 }; template<class Tax_cal> bank_calcu< Tax_cal>::bank_calcu(double money) :money(money) { tax_type = new Tax_cal();//給該指針分配內存 }; template<class Tax_cal> bank_calcu< Tax_cal>::~bank_calcu() { delete tax_type;//析構該內存 }; template<class Tax_cal> void bank_calcu< Tax_cal>::Calculate() { cout << tax_type->get_tax(money) << endl; } #endif // !STRATEGY
調用的過程爲:編碼
#include"strategy.h" int main() { bank_calcu<chinese_tax> t1(16000); t1.Calculate(); std::cin.get(); }
這樣調用起來就更加順手了。spa