动机(Motivation)
-
在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担。
-
如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?
模式定义
定义一系列算法,把它们一个个封装起来,并且使它们可互相替换(变化)。该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化)。 ——《设计模式》 GoF
要点总结
-
Strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换。
-
Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式。
-
如果Strategy对象没有实例变量,那么各个上下文可以共享同一个Strategy对象,从而节省对象开销。
不使用策略模式:
#include <iostream>
using namespace std;
enum TaxBase {
CN_Tax,
US_Tax,
DE_Tax,
FR_Tax //更改
};
class SalesOrder {
public:
void CalculateTax(TaxBase tax)
{
if (tax == CN_Tax)
{
cout << "CNTax" << endl;
}
else if (tax == US_Tax)
{
cout << "US_Tax" << endl;
}
else if (tax == DE_Tax)
{
cout << "DE_Tax" << endl;
}
//....
}
};
int main()
{
SalesOrder sale;
sale.CalculateTax(CN_Tax);
}
使用策略模式:
//strategy.h
#include <iostream>
using namespace std;
class TaxStrategy
{
public:
virtual void Calculate() = 0;
virtual ~TaxStrategy() {}
};
class CNTax : public TaxStrategy
{
public:
virtual void Calculate()
{
cout << "CNTax" << endl;
}
};
class USTax : public TaxStrategy
{
public:
virtual void Calculate()
{
cout << "USTax" << endl;
}
};
class DETax : public TaxStrategy
{
public:
virtual void Calculate()
{
cout << "DETax" << endl;
}
};
//扩展
//*********************************
class FRTax : public TaxStrategy
{
public:
virtual void Calculate()
{
cout << "FRTax" << endl;
}
};
//contex.h
#pragma once
#include "strategy.h"
//context
class SalesOrder
{
private:
TaxStrategy* m_strategy;
public:
SalesOrder(TaxStrategy* tax)
{
m_strategy = tax;
}
~SalesOrder()
{
delete m_strategy;
}
public:
void CalculateTax()
{
m_strategy->Calculate(); //多态调用
}
};
#include "contex.h"
int main()
{
TaxStrategy *tax = new DETax();
SalesOrder *sale = new SalesOrder(tax);
sale->CalculateTax();
}
在实际工程应用中采用简单工厂模式和策略模式相结合的方式来实现,show code:
//contex.h
#pragma once
#include "startegy.h"
enum TAX{
CN,
US,
DE
};
//context
class SalesOrder
{
private:
TaxStrategy* m_strategy;
public:
SalesOrder(TAX tax)
{
if (tax == CN)
m_strategy = new CNTax();
else if (tax == US)
m_strategy = new USTax();
//....
}
~SalesOrder()
{
delete m_strategy;
}
public:
void CalculateTax()
{
m_strategy->Calculate(); //多态调用
}
};
#include "contex.h"
int main()
{
TaxStrategy *tax = new DETax();
SalesOrder *sale = new SalesOrder(US);
sale->CalculateTax();
}
- 非策略模式:显得很臃肿,是一种紧耦合的写法。当需要添加新的tax的时候就需要修改代码功能,违背了开闭原则,正确的书写方式应该是扩展而不是修改。
- 策略模式则在需要增加新的tax的时候添加该tax即可,接口都已经留出了。原来书写的功能模块是独立的,不会相互影响,这就起到的松耦合的目的,当前功能只扩展而不是修改。