《设计模式》一书中对Strategy模式的意图叙述如下:
定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换,Strategy模式使算法可独立于使用它的客户而变化。
strategy模式以下列原则为基础:
1.对象都具有职责
2.这些职责不同的具体实现是通过多态的使用完成的
3.概念上相同的算法具有多个不同的实现,需要进行管理
Strategy模式:关键特征 | |
意图 |
可以根据所处的上下文,使用不同的业务规划或算法 |
问题 |
对所需算的选择取决于发出请求的客户或者要处理的数据。如果只有一些不会变化的算法,就不需要Strategy模式。 |
解决方案 |
将对算法的选择和算法的实现相分离。允许根据上下文进行选择。 |
参与者与协作者 |
|
效果 |
|
实现 |
让使用算法的类(Context)包含一个抽象类(Strategy),该抽象类有一个抽象方法指定如何调用算法。每个派生类按照需要实现算法。注意:在原型Strategy模式中,选择所用具有实现的职责由Client对象承担,并转给Strategy模式的Context对象。 |
Stategy模式的通用结构图
Strategy模式会带来爆炸性增长问题的解决方法
C++
可以用Strategy抽象类头文件包含所有ConcreteStrategy类的头文件。同时用|Strategy抽象类的cpp文件包含各ConcreteStrategy的代码。
Java
可以在Strategy抽象类内使用内部类包含所有的ConcreteStrategy。
但是如果无法控制所有的Strategy对象,也就是说如果有其它程序员需要实现自己的算法,就不要这么做。
代码示例:
TaxController.h
1 //TaxController.h 2 #pragma once 3 #include "CalcTax.h" 4 5 class TaskController 6 { 7 public: 8 TaskController(void); 9 void process(); 10 CalcTax *getTaxRulesForCountry(); 11 public: 12 ~TaskController(void); 13 }; 14 TaxController.cpp 15 #include "TaskController.h" 16 #include "SalesOrder.h" 17 #include "CalcTax.h" 18 #include "USTax.h" 19 20 TaskController::TaskController(void) 21 { 22 } 23 24 TaskController::~TaskController(void) 25 { 26 } 27 28 void TaskController::process () 29 { 30 // this code is an emulation of a 31 // processing task controller 32 // . . . 33 // figure out which country you are in 34 CalcTax *myTax; 35 myTax= getTaxRulesForCountry(); 36 SalesOrder *mySO= new SalesOrder(); 37 mySO->process( myTax); 38 } 39 40 CalcTax *TaskController::getTaxRulesForCountry() 41 { 42 // In real life, get the tax rules based on 43 // country you are in. You may have the 44 // logic here or you may have it in a 45 // configuration file 46 // Here, just return a USTax so this 47 // will compile. 48 return new USTax; 49 }
SalesOrder.h
1 //SalesOrder.h 2 #pragma once 3 #include "CalcTax.h" 4 5 class SalesOrder 6 { 7 public: 8 SalesOrder(void); 9 void process (CalcTax *TaxToUse); 10 public: 11 ~SalesOrder(void); 12 }; 13 SalesOrder.cpp 14 #include "SalesOrder.h" 15 16 SalesOrder::SalesOrder(void) 17 { 18 } 19 20 SalesOrder::~SalesOrder(void) 21 { 22 } 23 24 void SalesOrder::process (CalcTax *taxToUse) 25 { 26 long itemNumber= 0; 27 double price= 0; 28 29 // given the tax object to use 30 31 // . . . 32 33 // calculate tax 34 double tax= taxToUse->taxAmount( itemNumber, price); 35 }
CalcTax.h
1 //CalcTax.h 2 #pragma once 3 4 class CalcTax 5 { 6 public: 7 CalcTax(void); 8 double virtual taxAmount( long, double)= 0; 9 public: 10 ~CalcTax(void); 11 }; 12 CalcTax.cpp 13 #include "CalcTax.h" 14 15 CalcTax::CalcTax(void) 16 { 17 } 18 19 CalcTax::~CalcTax(void) 20 { 21 }
CanTax.h
1 //CanTax.h 2 #pragma once 3 #include "calctax.h" 4 5 class CanTax : 6 public CalcTax 7 { 8 public: 9 CanTax(void); 10 double taxAmount( long, double); 11 public: 12 ~CanTax(void); 13 }; 14 CanTax.cpp 15 #include "CanTax.h" 16 17 CanTax::CanTax(void) 18 { 19 } 20 21 CanTax::~CanTax(void) 22 { 23 } 24 25 double CanTax::taxAmount (long itemSold, double price) 26 { 27 // in real life, figure out tax according to 28 // the rules in Canada and return it 29 // here, return 0 so this will compile 30 return 0.0; 31 }
USTax.h
1 //USTax.h 2 #pragma once 3 #include "calctax.h" 4 5 class USTax : 6 public CalcTax 7 { 8 public: 9 USTax(void); 10 double taxAmount( long, double); 11 12 public: 13 ~USTax(void); 14 }; 15 USTax.cpp 16 #include "USTax.h" 17 18 USTax::USTax(void) 19 { 20 } 21 22 USTax::~USTax(void) 23 { 24 } 25 26 double USTax::taxAmount (long itemSold, double price) 27 { 28 // in real life, figure out tax according to 29 // the rules in the US and return it 30 // here, return 0 so this will compile 31 return 0.0; 32 }