组件协作模式
- 现在软件专业分工之后的第一个结果是“框架和应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之间的“松耦合”,是二者之间协作的常用模式
- 经典模式
动机
- 在软件的构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编写到对象中,将会使对象变得异常复杂,而且有时候支持不适用的算法也是一个性能负担。
- 如何在运行时根据需要透明的更改对象的算法?将算法与对象本身解耦,从而避免上述问题?
结构化设计写法
enum TaxBase
{
CN_Tax,
US_Tax,
DE_Tax
// ...
};
class SalesOrder
{
private:
TaxBase tax;
public:
double calculateTax()
{
// ...
if(tax == CN_Tax)
{
// CN******
}
else if(tax == US_Tax)
{
// US******
}
else if(tax == DE_Tax)
{
// DE******
}
// ...
}
};
如果要增加一个法国的税率,首先得增加枚举,然后在增加一个else if来增加新的,这违背了 开闭原则。
面向对象的写法
class TaxStrategy
{
public:
virtual double CalculateTax(const Context& context) = 0;
virtual ~TaxStratege();
};
class CNTax : public TaxStrategy
{
public:
virtual double CalculateTax(const Context& context)
{
// CN*******
}
};
class USTax : public TaxStrategy
{
public:
virtual double CalculateTax(const Context& context)
{
// US*******
}
};
class DETax : public TaxStrategy
{
public:
virtual double CalculateTax(const Context& context)
{
// DE*******
}
};
class SalesOrder {
private
TaxStrategy* strategy;
SalesOrder(StrategyFactory* strategyFactory) {
this->strategy = strategeFactory->NewStrategy();
}
~SalesOrder() {
delete this->strategy;
}
public double CalculateTax() {
// ...
Context context();
double val = strategy->CalculateTax(context);
// ...
}
};
这里增加一个法国的税率,就只需要写一个法国的税率类就可以了,不会改动其他类的代码,满足了开闭原则。SalesOrder 这个类得到了复用性。
模式定义
定义一系列算法,把他们一个个封装起来,并且他们可以互相替换(变化)。该模式使得算法可独立于使用他们的客户程序(稳定)而变化(扩展,子类化)。
类图
这里的Context就是面向对象代码中的SalesOrder 。
要点总结
- Strategy及其子类为组件提供了一系列可重用算法,从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换。
- Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是解耦合。含有许多条件判断语句的代码通常都需要Strategy模式。
- 如果Strategy对象没有实例变量,那么各个上下文可以共享同于一个Strategy对象(Strategy可以作为一个单例对象),从而节省对象开销。