C++11 简化 “策略模式” 的一种思路

676 阅读2分钟

「这是我参与11月更文挑战的第 12 天,活动详情查看:2021最后一次更文挑战」。

参加该活动的第 26 篇文章

正文

策略模式是一种定义一系列算法的模式,从概念上看,所有这些算法完成的都是相同接口的工作(只是实现不同),它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法的类之间的耦合。实践中只要在分析过程出现需要在不同时间应用相同接口的不同的业务规则,就可以考虑使用策略模式。

策略模式结构图

image.png

  • 抽象策略类,定义所有支持的算法的公共接口;
  • 具体策略类,封装了具体的算法或行为,继承自抽象策略类;
  • 上下文,由一个具体的策略类来配置,维护了一个策略对象的引用;

举例

以一个计算器为例,实现一个传统的策略模式,它具体分别实现了加法减法

/// @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 的复杂度也在增加,太松散了导致代码不够直观,代码的内聚性也变低了。

所以在此只是提供一个思路,具体问题还需要根据实际应用场景进行斟酌