文档目录

一、问题场景

传统策略模式(GoF 风格):

// 抽象策略类
struct CompressionStrategy {
    virtual std::vector<char> compress(const std::vector<char>&) = 0;
    virtual ~CompressionStrategy() = default;
};

struct GzipStrategy : CompressionStrategy { ... };
struct ZstdStrategy : CompressionStrategy { ... };

// 使用策略
class Compressor {
    std::unique_ptr<CompressionStrategy> strategy_;
public:
    void setStrategy(std::unique_ptr<CompressionStrategy> s) {
        strategy_ = std::move(s);
    }
};

问题:用户必须继承 CompressionStrategy、必须传 unique_ptr、必须处理所有权转移。

二、现代写法

class Compressor {
    // 用 std::function 替代虚基类
    std::function<std::vector<char>(const std::vector<char>&)> strategy_;

public:
    // 接受任何可调用对象:lambda、函数指针、函数对象
    void setStrategy(std::function<std::vector<char>(const std::vector<char>&)> s) {
        strategy_ = std::move(s);
    }

    std::vector<char> compress(const std::vector<char>& data) {
        if (!strategy_) throw std::runtime_error("no strategy set");
        return strategy_(data);
    }
};

// 使用——用户不需要继承任何东西
Compressor comp;
comp.setStrategy([](const auto& data) -> std::vector<char> {
    // 在这里写 gzip 压缩逻辑
    return data;
});

现代写法 vs 传统写法:

对比 传统虚基类 std::function
用户需要继承 是 否
用户需要传指针 是(unique_ptr) 否(值语义)
性能 一次虚函数调用 一次 TypeErasure 虚函数调用
灵活性 只能传继承的类 可传 lambda/函数/函数对象

再进一步:如果你在编译期就知道策略,可以用模板参数(零开销):

template <typename Strategy>
class Compressor {
    Strategy strategy_;
public:
    std::vector<char> compress(const std::vector<char>& data) {
        return strategy_.compress(data);
    }
};

// 零虚函数、零 TypeErasure、完全内联
Compressor<GzipStrategy> comp;