策略模式是一种定义一系列算法的模式,从概念上看,所有这些算法完成的都是相同接口的工作(只是实现不同),它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法的类之间的耦合。实践中只要在分析过程出现需要在不同时间应用相同接口的不同的业务规则,就可以考虑使用策略模式。比如:网关,因子,算法都可以进行抽象,使用策略模式,当然具体的策略对象可以用工厂模式组织,在Context里根据配置使用具体策略
简单工厂模式是创建型模式,关注对象的创建。策略模式是行为型模式,关注行为的封装。简单工厂模式是根据不同的条件返回一个适合的类给你使用,然后调用者使用工厂类返回的类去完成相应的操作。而策略模式是必须首先创建一个想使用的类实例,然后实例被当作参数传递进去,既而通过该实例去调用不用的算法(这个实例可以通过构造参数传入,也可以在构造函数内通过工厂模式获得,可以一个,也可以是多个实例),本人工作中在网关,因子设计时都使用了这种方式。
策略模式结构图
- 抽象策略类,定义所有支持的算法的公共接口;
- 具体策略类,封装了具体的算法或行为,继承自抽象策略类;
- 上下文,由一个具体的策略类来配置,维护了一个策略对象的引用;
举例
以一个计算器为例,实现一个传统的策略模式,它具体分别实现了加法和减法
/// @note 抽象策略类
class Calculater
{
public:
/// @note 支持的算法的公共接口
virtual int calculate(int x, int y) = 0;
};
/// @note 具体策略类 —— 减法
class Minus : public Calculater
{
public:
/// @note 具体的算法
int calculate(int x, int y)
{
return x - y;
}
};
/// @note 具体策略类 —— 加法
class Plus : public Calculater
{
public:
/// @note 具体的算法
int calculate(int x, int y)
{
return x + y;
}
};
/// @note 提供给外部使用的计算器类
class CalcuClient
{
private:
Calculater *m_caculater; ///< Context 上下文,即策略类对象的引用
public:
/// @note 设置上下文的接口
CalcuClient(Calculater *caculater) : m_caculater(caculater) {}
/// @note 根据设置的上下文,执行具体的计算
int calculate(int x, int y)
{
return m_caculater->calculate(x, y);
}
};
复制代码
如果改用 C++11 的 function 对象实现以上策略模式的代码的话,则代码可以大为精简,具体如下所示
class NewCalcuClient
{
private:
/// @note 接收外部设置的函数对象
std::function<int(int, int)> m_function;
public:
/// @note 设置具体的函数对象
NewCalcuClient(std::function<int(int, int)> function) : m_function(function) {}
/// @note 根据设置的函数对象具体执行
int calculate(int x, int y)
{
return m_function(x, y);
}
};
复制代码
总结
使用函数对象取代虚函数的一个理由是它去除了继承的限制,实现了松耦合,方法实现更加灵活,然而这个优点也可能成了它的缺点,当需要替代的虚函数增多时,组装function 的复杂度也在增加,太松散了导致代码不够直观,代码的内聚性也变低了。
所以在此只是提供一个思路,具体问题还需要根据实际应用场景进行斟酌。