一、问题场景
传统策略模式(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;