1. 为什么C++需要领域驱动设计?
在金融交易系统、游戏引擎、工业控制等复杂业务场景中,C++开发者常面临一个核心矛盾:业务规则日益复杂,但代码却难以直观反映业务语义。我曾参与过一个证券交易系统的重构,原始代码中充斥着这样的逻辑:
cpp复制void processOrder(double price, int quantity, string symbol) {
if (price <= 0 || quantity % 100 != 0 || symbol.empty()) {
throw invalid_argument("Invalid order");
}
// ...
}
这段代码暴露了三个典型问题:
- 基本类型(double/int/string)无法承载业务含义
- 校验逻辑分散在各处
- 业务规则(如手数必须是100的倍数)没有显式表达
领域驱动设计(DDD)通过以下方式解决这些问题:
- 将业务概念显式建模为领域对象
- 使用C++类型系统捕获业务规则
- 通过限界上下文划分复杂领域
2. C++强类型系统的业务表达力
2.1 从基本类型到领域类型
传统C++代码过度依赖基本类型,我们可以通过类型包装赋予业务语义:
cpp复制class Symbol {
string value;
static const regex pattern;
public:
explicit Symbol(const string& s) : value([&s]{
if (!regex_match(s, pattern))
throw invalid_argument("Invalid symbol format");
return s;
}()) {}
// ...
};
这种包装带来了三个优势:
- 编译时类型检查
- 集中化的校验逻辑
- 自文档化的接口
2.2 利用模板元编程实现业务规则
C++模板可以在编译期捕获业务不变式。例如,在电商系统中确保价格计算正确:
cpp复制template<typename Currency>
class Money {
static_assert(is_currency<Currency>::value, "Must be a valid currency");
long amount; // 以最小货币单位存储
// ...
};
通过特性检测(type traits),我们可以在编译时阻止非法货币运算。
3. 实体生命周期管理的C++实现模式
3.1 基于RAII的资源管理
在订单处理系统中,订单状态转换必须遵循严格规则:
cpp复制class Order {
enum class State { Draft, Validated, Executed, Cancelled };
State state = State::Draft;
class TransitionGuard {
Order& order;
State from, to;
public:
TransitionGuard(Order& o, State f, State t)
: order(o), from(f), to(t) {
if (order.state != from)
throw domain_error("Invalid state transition");
}
~TransitionGuard() { order.state = to; }
};
public:
void validate() {
TransitionGuard g(*this, State::Draft, State::Validated);
// 验证逻辑...
}
};
这种模式确保了:
- 状态转换的原子性
- 前置条件的强制检查
- 异常安全的状态回滚
3.2 领域事件的类型安全分发
使用variant和visit实现类型安全的事件处理:
cpp复制using OrderEvent = variant<OrderValidated, OrderExecuted, OrderCancelled>;
class OrderEventHandler {
public:
void handle(const OrderEvent& event) {
visit(overloaded {
[](const OrderValidated& e) { /*...*/ },
[](const OrderExecuted& e) { /*...*/ },
[](
