跳转到内容
新建笔记

C++ 策略模式:单位转换与明确的对象所有权

策略模式把一组可替换的算法放到统一接口后面,由持有策略的对象在运行时选择行为。原笔记以“米、毫米两种任务单位”为例;这里保留该场景,并明确策略的所有权、空值处理和单位换算。

对象职责
TaskStrategy约定输入如何转换成统一的米单位
MetricTaskStrategy输入已是米,保持数值
MillimeterTaskStrategy输入为毫米,除以 1000
Task独占一个有效策略,执行转换,允许替换策略

策略类型选择输入的解释方式,不能只更改显示后缀。1000 毫米应转换成 1 米,再交给使用统一单位的后续算法。

// C++17
#include <cassert>
#include <memory>
#include <stdexcept>
#include <utility>
class TaskStrategy {
public:
virtual ~TaskStrategy() = default;
virtual double toMeters(double value) const = 0;
};
class MetricTaskStrategy final : public TaskStrategy {
public:
double toMeters(double value) const override { return value; }
};
class MillimeterTaskStrategy final : public TaskStrategy {
public:
double toMeters(double value) const override { return value / 1000.0; }
};
class Task {
public:
explicit Task(std::unique_ptr<TaskStrategy> strategy) {
setStrategy(std::move(strategy));
}
Task(const Task &) = delete;
Task &operator=(const Task &) = delete;
Task(Task &&) = delete;
Task &operator=(Task &&) = delete;
void setStrategy(std::unique_ptr<TaskStrategy> strategy) {
if (!strategy) throw std::invalid_argument("strategy is required");
strategy_ = std::move(strategy);
}
double run(double value) const { return strategy_->toMeters(value); }
private:
std::unique_ptr<TaskStrategy> strategy_;
};
int main() {
Task task(std::make_unique<MetricTaskStrategy>());
assert(task.run(2.0) == 2.0);
task.setStrategy(std::make_unique<MillimeterTaskStrategy>());
assert(task.run(1000.0) == 1.0);
bool rejected = false;
try { task.setStrategy(nullptr); }
catch (const std::invalid_argument &) { rejected = true; }
assert(rejected);
assert(task.run(1000.0) == 1.0); // 无效替换没有破坏原策略
}

构造时必须提供有效策略,调用 run() 不依赖“调用者应该记得先 set”。替换时先检查新策略,再转移所有权,所以空策略被拒绝时旧策略仍可使用。

unique_ptr 让 Task 独占策略;替换策略或 Task 析构时,旧策略会自动释放。基类的虚析构函数保证经 TaskStrategy* 销毁具体策略时行为正确。此例显式禁止复制和移动 Task,避免产生仍可调用 run() 的空策略对象;若业务需要移动,应另外定义移后状态及其可用操作。unique_ptr、虚析构规则

如果策略由外部长期共享,也可选择非拥有引用或其他明确的管理方式,但应写清策略必须活多久。未初始化的裸指针既没有空值保护,也没有这样的寿命契约。

run() 与 setStrategy() 不能在不同线程无保护地同时调用;本例没有线程同步。跨线程共享时应另外定义并发访问规则。

只有简单单位换算时,一个明确的单位枚举和转换函数通常已经足够。策略模式适合需要扩展多套处理算法、算法有独立状态,或确实要在运行时替换行为的情况;它不要求为每一个常量都创建类。

相关基础:继承和多态。原始记录:CSDN。