您的位置:首页 > 其它

设计模式学习总结:策略模式(Strategy Pattern)

2017-10-31 14:23 309 查看

意图

定义算法族,将它们分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于算法的客户。

适用性

许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。

需用使用一个算法的不同变体

算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。

一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现。则可以将相关的条件分支迁入它们各自的strategy类中。

结构

优缺点

优点

封装了算法,是算法可以得到复用

通过将算法独立于客户,使系统更有弹性,使客户可以随时切换算法,易于理解与扩展

可以消除一些条件语句

可以提供相同行为的不同实现

缺点

客户在选择一个合适的strategy必须了解这些strategy之间有何不同,因此仅当这些不同行为是与客户相关的行为时,才需要使用strategy模式

strategy和context之间存在通信开销

增加了类与对象的数目。有时你可以将strategy实现为可供context共享的无状态的对象来减少这一开销。任何其余的状态均由context维护,context在每次对strategy的请求中都将这个状态传递过去。享元(FlyWeight)模式更详细地描述了这一方法。

实现

考虑以下几个实现问题:

1.实际实现中Strategy必须要获取context中的数据。

一种方法是让context将所需数据作为参数传给strategy,这让strategy与context解耦,但在所需数据较多时接口参数将会很多,而且可能会发送一些strategy不需要的参数。

class Context
{
public:
void Operation(){_theStrategy.DoAlgorithm(_data1, _data2);}
private:
Strategy _theStrategy;
int _data1;
int _data2;
}

class Strategy
{
public:
void DoAlgorithm(int data1, int data2)
{
...
}
}


另一种方法是将context自身作为参数传递给strategy,然后strategy显式地想context请求数据,但这样strategy与context更紧密地耦合在一起,而且需要为context定义更为精细的数据接口。

class Context
{
public:
void Operation(){_theStrategy.DoAlgorithm(this);}
private:
Strategy _theStrategy;
int _data1;
int _data2;
float _data3;
float _data4;
double _data5;
}

class Strategy
{
public:
void DoAlgorithm(const Context& context)
{
...
}
}


2.当一个context类可以在编译时确定其strategy并且在运行时不会改变其strategy时,则可以将context定义为一个以strategy类作为一个模板参数的模板类,如下:

template<class Strategy>
class Context
{
public:
void Operation(){_theStrategy.DoAlgorithm();}
private:
Strategy _theStrategy;
}

//两个不同的策略不需要从一个基类Strategy中继承
class StrategyA
{
public:
void DoAlgorithm();
}

class StrategyB
{
public:
void DoAlgorithm();
}

Context<StrategyA> contextA;
Context<StrategyB> contextB;


这样使用模板不再需要定义给Strategy定义的抽象类,通过将一个Strategy和它的Context静态绑定在一起,从而提高效率。

相关模式

享元(FlyWeight)模式:Strategy对象通常是很好的轻量级对象。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: