動機(Motivation)
- 在軟件構建過程中,某些對象使用的算法可能多種多樣,經常改變,如果將這些算法都編碼到對象中,將會使對象變得異常複雜;而且有時候支持不使用的算法也是一個性能負擔。
- 如何在運行時根據需要透明地更改對象的算法?將算法與對象本身解耦,從而避免上述問題?
模式定義
- 定義一系列算法,把它們一個個封裝起來,並且使它們可互相替換(變化)。該模式使得算法可獨立於使用它的客戶程序(穩定)而變化(擴展,子類化)。
要點總結
- Strategy及其子類爲組件提供了一系列可重用的算法,從而可以使得類型在運行時方便地根據需要在各個算法之間進行切換。
- Strategy模式提供了用條件判斷語句以外的另一種選擇,消除條件判斷語句,就是在解耦合。含有許多條件判斷語句的代碼通常都需要Strategy模式。
- 如果Strategy對象沒有實例變量,那麼各個上下文可以共享同一個Strategy對象,從而節省對象開銷。
示例
示例1(不使用Strategy):
enum TaxBase {
CN_Tax,
US_Tax,
DE_Tax,
FR_Tax //更改
};
class SalesOrder{
TaxBase tax;
public:
double CalculateTax(){
//...
if (tax == CN_Tax){
//CN***********
}
else if (tax == US_Tax){
//US***********
}
else if (tax == DE_Tax){
//DE***********
}
else if (tax == FR_Tax){ //更改
//...
}
//....
}
};
分析:
上述代碼中使用枚舉類型 TaxBase 和 if - else 將不同的算法編碼到同一對象中。如需增加新的算法,必須修改對象中的代碼(增加一個 else if 以及枚舉類型),這違背了開放封閉原則。
示例2(使用Strategy):
class TaxStrategy{
public:
virtual double Calculate(const Context& context)=0;
virtual ~TaxStrategy(){}
};
class CNTax : public TaxStrategy{
public:
virtual double Calculate(const Context& context){
//***********
}
};
class USTax : public TaxStrategy{
public:
virtual double Calculate(const Context& context){
//***********
}
};
class DETax : public TaxStrategy{
public:
virtual double Calculate(const Context& context){
//***********
}
};
//擴展
//*********************************
class FRTax : public TaxStrategy{
public:
virtual double Calculate(const Context& context){
//.........
}
};
class SalesOrder{
private:
TaxStrategy* strategy;
public:
// 工廠模式
SalesOrder(StrategyFactory* strategyFactory){
this->strategy = strategyFactory->NewStrategy();
}
~SalesOrder(){
delete this->strategy;
}
public double CalculateTax(){
//...
Context context();
double val =
strategy->Calculate(context); //多態調用
//...
}
};
分析:
上述代碼中定義一系列算法,把它們一個個封裝起來(成爲多個子類),使得算法可獨立於使用它的客戶程序 SalesOrder 而變化。如需增加新的算法,只需增加新的子類即可。
參考鏈接: