设计模式(三)- Strategy

设计动机

  1. 对象使用的算法多变,若都编码在对象中,使得对象复杂
  2. 运行时根据需要透明的更改对象算法,将算法与对象本身解耦

定义

定义一系列算法,把它们一个个封装起来,并且使它们可互相替换((变化)。该模式使得算法可独立于使用它的客户程序稳定)而变化(扩展,子类化)。

结构

结构

例子

传统分而治之

采用大量的if-else语句进行情况的选择,在编译阶段代码无法实现复用。每次需要增添一种货币的计算方式时,都必须在源代码下方增添if-else来实现相关策略的选择

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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){ //¸ü¸Ä
//...
}

//....
}

};

采用策略模式

构建策略基类,所有真实情况的货币类都是该策略基类的派生类,利用多态机制实现策略的选择

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//策略基类
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){
//***********
}
};



//针对新增的FRTax,只需要重新派生该类并定义相关算法即可
//*********************************
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);
//...
}

};

总结

  1. Strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换。

  2. Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语苟,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式。(如果if-else是绝对稳定不变的,不太需要strategy模式)

  3. 如果Strategy对象没有实例变量,那么各个上下文可以共享同一个Strategy对象,从而节省对象开销。

PatternDesign03