1. 项目概述
CPP-Summit-2020是C++领域的一次重要技术峰会,其中"面向领域模型的C++实现模式"这个话题引起了我的特别关注。作为一位长期使用C++进行复杂系统开发的工程师,我发现领域模型在现代软件开发中扮演着越来越重要的角色,而C++作为一门系统级语言,如何优雅地实现领域模型一直是个值得深入探讨的话题。
这次分享实际上是之前讨论的延续,主要聚焦于如何在C++中应用领域驱动设计(DDD)原则,以及如何利用现代C++特性来构建更清晰、更易维护的领域模型。这个话题特别吸引我的地方在于,它不仅仅停留在理论层面,而是提供了大量可落地的实现模式和最佳实践。
2. 领域模型与C++的结合价值
2.1 为什么要在C++中实现领域模型
传统上,领域驱动设计更多见于Java、C#等托管语言环境,而C++由于其系统级特性,往往被用于性能敏感或资源受限的场景。但随着软件复杂度不断提升,即使是系统级软件也需要良好的架构设计来应对变化。
在C++中实现领域模型有几个显著优势:
- 性能优势:领域模型的核心逻辑可以直接运行在裸机或嵌入式环境
- 内存控制:可以精确控制对象生命周期和内存布局
- 与现代C++特性的结合:利用C++11/14/17/20的新特性可以写出更优雅的领域代码
2.2 领域模型在C++项目中的典型应用场景
从我参与过的项目来看,C++领域模型特别适合以下场景:
- 金融交易系统:需要高性能且业务规则复杂的系统
- 游戏引擎:实体组件系统(ECS)本质上就是一种领域模型
- 工业控制系统:需要精确建模物理设备和工艺流程
- 通信协议栈:协议状态机和消息处理可以很好地用领域模型表达
3. 核心实现模式解析
3.1 值对象(Value Object)的实现
值对象是领域模型中的基础构建块,在C++中我们可以充分利用其值语义特性:
cpp复制class Money {
public:
Money(double amount, Currency currency)
: amount_(amount), currency_(currency) {}
bool operator==(const Money& other) const {
return amount_ == other.amount_
&& currency_ == other.currency_;
}
// 其他算术运算符重载...
private:
double amount_;
Currency currency_;
};
关键实现要点:
- 确保值对象的不可变性(const成员或私有setter)
- 正确实现operator==和operator!=
- 考虑实现operator<=>(C++20起)
- 提供完整的值语义(拷贝构造、移动语义等)
3.2 实体(Entity)的实现模式
实体与值对象的关键区别在于标识符(Identity)。在C++中实现实体时需要注意:
cpp复制class Order {
public:
explicit Order(OrderId id) : id_(id) {}
OrderId id() const { return id_; }
void addItem(ProductId product, int quantity) {
// 业务逻辑验证...
items_.emplace_back(product, quantity);
}
// 其他方法...
private:
OrderId id_;
std::vector<OrderItem> items_;
// 其他状态...
};
实现技巧:
- 使用强类型ID(而非原始类型)作为标识符
- 保持实体行为的完整性(避免贫血模型)
- 考虑使用std::unique_ptr管理复杂实体的生命周期
- 谨慎处理实体的拷贝语义(通常禁用拷贝)
3.3 聚合根(Aggregate Root)的实现
聚合根是领域模型中最具挑战性的部分,在C++中需要特别注意内存管理和事务边界:
cpp复制class ShoppingCart {
public:
void addItem(ProductId product, int quantity) {
// 验证业务规则
if (items_.size() >= MAX_ITEMS) {
throw CartFullError();
}
// 应用变更
auto it = findItem(product);
if (it != items_.end()) {
it->increaseQuantity(quantity);
} else {
items_.emplace_back(product, quantity);
}
}
// 其他聚合根方法...
private:
std::vector<CartItem> items_;
// 其他聚合内对象...
};
关键考量:
- 确保聚合内的不变条件(invariants)始终满足
- 控制聚合的大小(避免过大聚合)
- 使用工厂方法或构造函数保证聚合的有效性
- 考虑使用std::shared_ptr或引用语义处理聚合间引用
4. 现代C++特性在领域模型中的应用
4.1 使用constexpr实现编译时领域逻辑
现代C++的constexpr特性允许我们在编译期执行领域逻辑:
cpp复制constexpr bool isValidProductCode(int code) {
return code > 1000 && code < 9999;
}
static_assert(isValidProductCode(1234), "Valid product code");
static_assert(!isValidProductCode(9999), "Invalid product code");
这种技术特别适合:
- 领域常量验证
- 简单的业务规则检查
- 配置参数的编译时验证
4.2 使用concepts(C++20)约束领域类型
C++20的concepts可以显著改善领域模型的类型安全:
cpp复制template<typename T>
concept Orderable = requires(T a, T b) {
{ a < b } -> std::convertible_to<bool>;
};
template<Orderable T>
class SortedCollection {
// 实现依赖于<运算符的集合
};
应用场景:
- 定义领域特定类型约束
- 使模板代码更安全
- 提供更好的错误消息
4.3 使用std::variant实现领域状态机
领域模型中的状态模式可以用std::variant优雅实现:
cpp复制struct OrderPending {};
struct OrderApproved {};
struct OrderShipped {};
struct OrderCancelled {};
using OrderState = std::variant<
OrderPending,
OrderApproved,
OrderShipped,
OrderCancelled
>;
class Order {
public:
void approve() {
state_ = std::visit([](auto&& arg) -> OrderState {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, OrderPending>) {
return OrderApproved{};
} else {
throw InvalidOrderState();
}
}, state_);
}
// 其他状态转换方法...
private:
OrderState state_;
};
这种实现方式:
- 类型安全
- 避免虚函数开销
- 编译时可检查状态转换
5. 性能与内存考量
5.1 领域对象的内存布局优化
在性能敏感的场景中,需要考虑领域对象的内存布局:
cpp复制// 传统OO风格 - 虚函数导致间接调用和内存分散
class Product {
public:
virtual ~Product() = default;
virtual double calculatePrice() const = 0;
};
// 数据导向设计 - 更好的缓存局部性
struct Products {
std::vector<int> ids;
std::vector<double> basePrices;
std::vector<double> discounts;
double calculatePrice(size_t index) const {
return basePrices[index] * (1.0 - discounts[index]);
}
};
选择建议:
- 对核心领域考虑数据导向设计
- 对复杂多态使用传统OO
- 使用std::variant作为"穷人的多态"
5.2 领域事件的实现与性能
领域事件是DDD中的重要模式,在C++中需要平衡灵活性和性能:
cpp复制class OrderCancelledEvent {
public:
explicit OrderCancelledEvent(OrderId id, std::string reason)
: id_(id), reason_(std::move(reason)) {}
OrderId id() const { return id_; }
const std::string& reason() const { return reason_; }
private:
OrderId id_;
std::string reason_;
};
// 事件发布者
class EventPublisher {
public:
template<typename Event>
void publish(Event&& event) {
for (auto& handler : handlers_) {
handler->handle(std::forward<Event>(event));
}
}
// 注册处理程序...
private:
std::vector<std::unique_ptr<EventHandler>> handlers_;
};
性能优化技巧:
- 考虑使用内存池分配事件对象
- 对高频事件使用特化版本
- 评估同步vs异步事件处理
6. 测试策略与可维护性
6.1 领域模型的单元测试
C++领域模型的测试有其特殊性:
cpp复制TEST(OrderTest, ShouldAddItemToEmptyOrder) {
Order order(OrderId{1});
order.addItem(ProductId{100}, 2);
ASSERT_EQ(1, order.itemCount());
ASSERT_EQ(2, order.itemQuantity(ProductId{100}));
}
TEST(OrderTest, ShouldNotAllowDuplicateItems) {
Order order(OrderId{1});
order.addItem(ProductId{100}, 1);
EXPECT_THROW(
order.addItem(ProductId{100}, 1),
DuplicateItemError
);
}
测试建议:
- 每个测试用例聚焦一个行为
- 使用GTest或Catch2等现代测试框架
- 考虑使用模拟对象处理外部依赖
- 测试领域不变量和业务规则
6.2 领域模型的文档化
良好的文档对领域模型的维护至关重要:
cpp复制/**
* @class Order
* @brief 表示客户订单的聚合根
*
* 负责维护订单的生命周期和不变规则:
* - 订单项不能超过MAX_ITEMS
* - 已发货订单不能修改
* - 总金额必须>=0
*/
class Order {
// 实现...
};
文档化策略:
- 使用Doxygen风格注释
- 为重要领域概念添加示例代码
- 维护领域术语表
- 图示关键聚合关系
7. 常见问题与解决方案
7.1 循环依赖问题
在领域模型中,聚合之间有时需要相互引用:
解决方案1:使用弱引用
cpp复制class Order {
std::weak_ptr<Customer> customer_;
};
解决方案2:使用ID引用
cpp复制class Order {
CustomerId customerId_;
};
选择依据:
- 如果需要频繁导航,使用弱引用
- 如果关系较松散,使用ID引用
- 考虑使用中介者模式解耦
7.2 领域模型与持久化的阻抗失配
将领域模型持久化到数据库时的挑战:
策略1:使用数据映射器(Data Mapper)
cpp复制class OrderMapper {
public:
Order findById(OrderId id);
void save(const Order& order);
};
策略2:使用工作单元(Unit of Work)模式
cpp复制class UnitOfWork {
public:
void registerNew(DomainObject* obj);
void registerDirty(DomainObject* obj);
void commit();
};
实施建议:
- 考虑使用现成的ORM库(如ODB)
- 对高性能场景使用手工编码的映射器
- 明确区分领域模型和数据模型
7.3 多线程环境下的领域模型
线程安全的领域模型实现技巧:
- 不变性优先:尽可能设计不可变对象
- 细粒度锁:保护小的临界区
- 领域事件:使用消息传递代替共享状态
- 线程局部存储:某些场景下可以使用thread_local
示例:
cpp复制class ThreadSafeAccount {
public:
void deposit(double amount) {
std::lock_guard<std::mutex> lock(mutex_);
balance_ += amount;
}
private:
double balance_;
mutable std::mutex mutex_;
};
8. 从传统OO到函数式领域模型
8.1 不可变领域模型
函数式风格在领域模型中的应用:
cpp复制struct ImmutableOrder {
OrderId id;
std::vector<OrderItem> items;
ImmutableOrder addItem(OrderItem item) const {
auto newItems = items;
newItems.push_back(item);
return {id, std::move(newItems)};
}
};
优势:
- 线程安全
- 更容易推理
- 更好的测试性
挑战:
- 性能开销(需要拷贝)
- C++语法不如函数式语言简洁
8.2 使用std::function实现策略模式
将业务规则抽象为可配置的策略:
cpp复制class PricingCalculator {
public:
using DiscountStrategy = std::function<double(double)>;
PricingCalculator(DiscountStrategy strategy)
: strategy_(std::move(strategy)) {}
double calculateFinalPrice(double basePrice) const {
return strategy_(basePrice);
}
private:
DiscountStrategy strategy_;
};
应用场景:
- 可插拔的业务规则
- 运行时配置的策略
- A/B测试不同算法
9. 领域模型与现有代码的集成
9.1 逐步引入领域模型
在遗留系统中引入领域模型的策略:
- 从核心子域开始
- 创建防腐层(Anti-Corruption Layer)
- 逐步替换事务脚本
- 使用外观模式提供过渡接口
示例防腐层:
cpp复制class LegacyOrderAdapter {
public:
explicit LegacyOrderAdapter(LegacyOrderSystem& system)
: system_(system) {}
std::unique_ptr<Order> findOrder(OrderId id) {
auto legacyOrder = system_.getOrder(id.value());
return convertToDomainModel(legacyOrder);
}
// 其他转换方法...
private:
LegacyOrderSystem& system_;
};
9.2 领域模型与第三方库的协作
如何让领域模型与现有库协同工作:
策略1:适配器模式
cpp复制class JsonOrderSerializer {
public:
static std::string serialize(const Order& order);
static Order deserialize(std::string_view json);
};
策略2:领域服务包装
cpp复制class PaymentProcessingService {
public:
PaymentResult processPayment(
const Order& order,
PaymentMethod method
) {
// 调用第三方支付库
return paymentProcessor_.charge(
order.totalAmount(),
method
);
}
private:
ThirdPartyPaymentProcessor paymentProcessor_;
};
10. 领域特定语言(DSL)的应用
10.1 嵌入式DSL实现业务规则
利用C++运算符重载创建流畅接口:
cpp复制auto rule = (account.balance() >= min_balance)
&& (account.age() > 30_days)
&& !account.isFrozen();
实现技术:
- 表达式模板
- 运算符重载
- 延迟求值
10.2 使用宏简化领域代码
谨慎使用宏定义领域术语:
cpp复制#define DEFINE_ID_TYPE(Name) \
struct Name { \
int value; \
explicit Name(int v) : value(v) {} \
bool operator==(const Name&) const = default; \
}
DEFINE_ID_TYPE(OrderId);
DEFINE_ID_TYPE(ProductId);
DEFINE_ID_TYPE(CustomerId);
注意事项:
- 仅在确实提高可读性时使用宏
- 确保宏有明确的命名和作用域
- 考虑使用模板替代复杂宏
11. 跨平台领域模型的考量
11.1 处理平台差异
确保领域模型在不同平台上行为一致:
- 固定基本类型大小(使用std::int32_t等)
- 避免平台特定的行为(如字节序)
- 隔离平台相关代码
cpp复制class NetworkOrder {
public:
uint32_t id() const {
return ntohl(rawId_); // 网络字节序转换
}
private:
uint32_t rawId_;
};
11.2 嵌入式环境的特殊考量
资源受限环境下的领域模型优化:
- 使用静态分配代替动态内存
- 简化异常处理(考虑返回错误码)
- 优化领域对象大小
cpp复制template<size_t MaxItems>
class FixedSizeOrder {
public:
bool addItem(ProductId product, int quantity) {
if (count_ >= MaxItems) return false;
items_[count_++] = {product, quantity};
return true;
}
private:
OrderItem items_[MaxItems];
size_t count_ = 0;
};
12. 性能分析与优化
12.1 领域模型的热点分析
使用性能工具识别瓶颈:
- 使用perf或VTune分析调用热点
- 检查缓存命中率
- 分析内存访问模式
常见优化点:
- 虚函数调用开销
- 缓存不友好的数据布局
- 不必要的拷贝
12.2 领域对象的池化技术
重用领域对象以减少分配开销:
cpp复制class OrderPool {
public:
Order* createOrder(OrderId id) {
if (freeList_.empty()) {
allocateChunk();
}
auto order = freeList_.back();
freeList_.pop_back();
new (order) Order(id);
return order;
}
void releaseOrder(Order* order) {
order->~Order();
freeList_.push_back(order);
}
private:
std::vector<Order*> freeList_;
};
适用场景:
- 高频创建/销毁的对象
- 固定大小的对象
- 实时性要求高的系统
13. 领域模型的演化与版本控制
13.1 处理领域模型的变更
向后兼容的模型演化策略:
- 使用版本化序列化格式
- 提供迁移路径
- 保持旧代码直到所有客户端迁移
cpp复制class OrderV2 : public Order {
public:
// 新增字段
std::optional<DiscountCoupon> coupon() const;
// 兼容旧版本序列化
static std::unique_ptr<OrderV2> fromV1(const Order& v1);
};
13.2 领域模型的分支策略
团队协作时的模型管理:
- 每个有界上下文独立演进
- 使用共享内核处理公共模型
- 定期进行上下文映射
技术实现:
- 命名空间隔离
- 库版本控制
- 接口兼容性保证
14. 领域模型可视化与沟通
14.1 使用C++代码表达领域概念
让代码本身成为文档的技术:
- 使用富有表现力的类型名
- 保持方法与领域术语一致
- 组织代码反映领域结构
cpp复制namespace shipping {
namespace domain {
class ContainerShipment {
public:
void assignContainer(ContainerId id);
void addCargo(Cargo cargo);
void prepareForDeparture();
};
} // namespace domain
} // namespace shipping
14.2 生成领域模型图
从代码生成可视化模型:
- 使用Doxygen生成类图
- 自定义工具提取关键关系
- 保持代码与图表同步
工具建议:
- PlantUML
- Graphviz
- 企业架构工具集成
15. 领域模型与架构模式
15.1 六边形架构中的领域模型
将领域模型置于架构中心:
cpp复制// 领域层
class OrderService {
public:
virtual void placeOrder(const Order& order) = 0;
};
// 基础设施层
class DatabaseOrderService : public OrderService {
public:
void placeOrder(const Order& order) override;
};
// 应用层
class OrderController {
public:
explicit OrderController(OrderService& service);
void handlePlaceOrder(HttpRequest& request);
};
分层原则:
- 领域层不依赖其他层
- 基础设施层实现领域接口
- 应用层协调工作流
15.2 CQRS模式下的领域模型
命令查询职责分离的实现:
cpp复制// 命令端 - 处理状态变更
class OrderCommandHandler {
public:
void handle(PlaceOrderCommand cmd);
void handle(CancelOrderCommand cmd);
};
// 查询端 - 优化读取
class OrderQueryService {
public:
OrderView getOrderView(OrderId id);
std::vector<OrderView> searchOrders(OrderFilter filter);
};
实施建议:
- 明确区分命令和查询模型
- 考虑使用不同数据存储
- 使用事件保持同步
16. 领域模型与设计模式
16.1 策略模式实现业务规则
灵活的业务规则配置:
cpp复制class PricingStrategy {
public:
virtual double calculatePrice(double base) const = 0;
};
class StandardPricing : public PricingStrategy {
double calculatePrice(double base) const override {
return base;
}
};
class DiscountPricing : public PricingStrategy {
double calculatePrice(double base) const override {
return base * 0.9;
}
};
16.2 装饰器模式增强领域对象
运行时扩展领域对象行为:
cpp复制class Order {
public:
virtual double total() const = 0;
};
class BasicOrder : public Order {
double total() const override;
};
class OrderWithTax : public Order {
public:
OrderWithTax(std::unique_ptr<Order> inner, double rate)
: inner_(std::move(inner)), rate_(rate) {}
double total() const override {
return inner_->total() * (1.0 + rate_);
}
private:
std::unique_ptr<Order> inner_;
double rate_;
};
17. 领域模型与并发模式
17.1 使用Actor模型处理领域逻辑
基于消息传递的并发模型:
cpp复制class OrderActor {
public:
void receive(Message msg) {
std::visit(overloaded {
[this](PlaceOrder& cmd) { /* 处理命令 */ },
[this](QueryOrder& query) { /* 处理查询 */ }
}, msg);
}
private:
OrderState state_;
};
实现选项:
- 使用现成的Actor框架(如CAF)
- 基于std::async实现简单版本
- 考虑协程(C++20)简化异步代码
17.2 无锁领域数据结构
高性能并发领域对象的实现:
cpp复制class LockFreeAccount {
public:
void deposit(double amount) {
balance_.fetch_add(amount, std::memory_order_relaxed);
}
bool withdraw(double amount) {
double current = balance_.load(std::memory_order_relaxed);
while (current >= amount) {
if (balance_.compare_exchange_weak(
current, current - amount,
std::memory_order_release,
std::memory_order_relaxed)) {
return true;
}
}
return false;
}
private:
std::atomic<double> balance_;
};
适用场景:
- 极高并发访问
- 低延迟要求
- 简单状态变更
18. 领域模型与异常处理
18.1 领域特定异常设计
表达业务错误的异常层次:
cpp复制class DomainException : public std::exception {
// 基础领域异常
};
class InsufficientFunds : public DomainException {
// 特定业务异常
};
class InventoryShortage : public DomainException {
// 特定业务异常
};
最佳实践:
- 保持异常层次扁平
- 包含足够的诊断信息
- 考虑错误码替代异常(嵌入式场景)
18.2 异常安全与事务一致性
确保领域操作的事务性:
cpp复制class OrderProcessor {
public:
void process(Order& order) {
auto checkpoint = createCheckpoint();
try {
validate(order);
reserveInventory(order);
chargePayment(order);
confirm(order);
} catch (...) {
rollbackTo(checkpoint);
throw;
}
}
};
技术选项:
- 事务日志
- 补偿事务
- 两阶段提交
19. 领域模型与缓存策略
19.1 领域对象缓存实现
提高领域模型访问性能:
cpp复制class OrderCache {
public:
std::shared_ptr<Order> get(OrderId id) {
std::lock_guard lock(mutex_);
if (auto it = cache_.find(id); it != cache_.end()) {
return it->second.lock();
}
return loadOrder(id);
}
private:
std::shared_ptr<Order> loadOrder(OrderId id);
std::mutex mutex_;
std::unordered_map<OrderId, std::weak_ptr<Order>> cache_;
};
缓存策略:
- LRU缓存
- 时间过期
- 写穿透/写回
19.2 领域查询的结果缓存
优化复杂查询性能:
cpp复制class OrderReportService {
public:
OrderSummary getSummary(OrderFilter filter) {
auto key = makeCacheKey(filter);
if (auto it = cache_.find(key); it != cache_.end()) {
return it->second;
}
auto result = calculateSummary(filter);
cache_.emplace(key, result);
return result;
}
private:
std::unordered_map<std::string, OrderSummary> cache_;
};
注意事项:
- 缓存失效策略
- 内存使用监控
- 并发访问控制
20. 领域模型与分布式系统
20.1 分布式领域对象标识
全局唯一ID生成策略:
cpp复制class OrderIdGenerator {
public:
OrderId generate() {
// 雪花算法实现
auto now = std::chrono::system_clock::now();
auto timestamp = now.time_since_epoch().count();
std::lock_guard lock(mutex_);
if (lastTimestamp_ == timestamp) {
++sequence_;
} else {
sequence_ = 0;
}
lastTimestamp_ = timestamp;
return OrderId{
(timestamp << 22) |
(nodeId_ << 12) |
sequence_
};
}
private:
int64_t nodeId_;
int64_t lastTimestamp_ = 0;
uint16_t sequence_ = 0;
std::mutex mutex_;
};
其他选项:
- UUID
- 数据库序列
- 集中式ID服务
20.2 领域事件与消息队列
跨服务集成的事件驱动架构:
cpp复制class OrderEventPublisher {
public:
void publishOrderCreated(const Order& order) {
OrderCreatedEvent event{
order.id(),
order.customerId(),
order.totalAmount()
};
queue_.publish("order.created", serialize(event));
}
private:
MessageQueue& queue_;
};
集成考虑:
- 事件序列化格式(JSON/Protobuf等)
- 消息可靠性保证
- 事件版本兼容性
21. 领域模型与微服务架构
21.1 微服务边界的领域划分
将领域模型映射到微服务:
- 每个有界上下文对应一个服务
- 明确服务间契约
- 处理分布式事务挑战
cpp复制// 订单服务
class OrderService {
void createOrder(OrderRequest request);
};
// 支付服务
class PaymentService {
void processPayment(PaymentRequest request);
};
// 库存服务
class InventoryService {
void reserveStock(ReservationRequest request);
};
21.2 领域模型的API设计
微服务API的领域表达:
cpp复制// RESTful 资源设计
class OrderResource {
public:
Response getOrder(OrderId id);
Response createOrder(OrderRequest request);
Response cancelOrder(OrderId id);
};
// gRPC 服务设计
service OrderService {
rpc GetOrder (OrderId) returns (Order);
rpc CreateOrder (OrderRequest) returns (Order);
rpc CancelOrder (OrderId) returns (Empty);
}
设计原则:
- 反映领域概念
- 保持操作幂等
- 考虑版本策略
22. 领域模型与测试驱动开发
22.1 TDD中的领域模型演进
从测试驱动领域模型设计:
cpp复制TEST(OrderTest, ShouldCalculateTotalWithTax) {
Order order;
order.addItem(ProductId{1}, 2, 10.0); // 2 x $10
order.setTaxRate(0.1); // 10% tax
ASSERT_DOUBLE_EQ(22.0, order.total()); // $20 + $2 tax
}
TDD循环:
- 编写失败的领域测试
- 实现最简单的通过方案
- 重构改进设计
- 重复
22.2 领域模型的模拟测试
隔离测试领域对象:
cpp复制class MockPaymentGateway : public PaymentGateway {
public:
MOCK_METHOD(bool, charge, (double, PaymentMethod), (override));
};
TEST(OrderProcessorTest, ShouldProcessPayment) {
MockPaymentGateway gateway;
EXPECT_CALL(gateway, charge(100.0, _))
.WillOnce(Return(true));
OrderProcessor processor(gateway);
Order order(/* total= */ 100.0);
ASSERT_TRUE(processor.process(order));
}
模拟策略:
- 仅模拟外部依赖
- 避免过度指定
- 关注领域行为而非实现
23. 领域模型的重构技巧
23.1 识别贫血模型并改进
将数据与行为重新结合:
重构前:
cpp复制struct OrderData {
OrderId id;
std::vector<OrderItem> items;
};
class OrderService {
public:
double calculateTotal(const OrderData& order);
};
重构后:
cpp复制class Order {
public:
double total() const {
double sum = 0;
for (const auto& item : items_) {
sum += item.subtotal();
}
return sum;
}
private:
std::vector<OrderItem> items_;
};
重构步骤:
- 识别只有getter/setter的"数据类"
- 将相关行为移入类中
- 确保不变量的维护
23.2 拆分过大领域类
识别并分解过大的领域对象:
拆分信号:
- 类有太多职责
- 方法组操作不同数据子集
- 经常需要部分更新
重构技术:
- 提取新类
- 使用组合代替继承
- 引入领域服务
24. 领域模型与代码生成
24.1 使用元编程生成领域代码
减少样板代码的技术:
cpp复制#define DEFINE_ENTITY(NAME, ID_TYPE) \
class NAME { \
public: \
explicit NAME(ID_TYPE id) : id_(id) {} \
ID_TYPE id() const { return id_; } \
bool operator==(const NAME& other) const { \
return id_ == other.id_; \
} \
private: \
ID_TYPE id_; \
}
DEFINE_ENTITY(Order, OrderId);
DEFINE_ENTITY(Product, ProductId);
高级选项:
- 使用模板元编程
- 自定义代码生成器
- 反射(C++未来可能支持)
24.2 从DSL生成领域模型
领域特定语言到C++的转换:
示例DSL:
code复制entity Order {
id: OrderId
items: List<OrderItem>
status: OrderStatus
}
生成结果:
cpp复制class Order {
public:
OrderId id() const;
const std::vector<OrderItem>& items() const;
OrderStatus status() const;
private:
OrderId id_;
std::vector<OrderItem> items_;
OrderStatus status_;
};
工具选项:
- ANTLR等解析器生成器
- 自定义词法分析
- 模板引擎
25. 领域模型与架构决策记录
25.1 记录关键领域设计决策
架构决策记录(ADR)示例:
code复制# 1. 订单标识符方案
## 状态
已接受
## 上下文
需要唯一标识跨服务边界的订单
## 决策
使用雪花算法生成的64位整数作为订单ID
## 后果
- 优点:分布式生成,无需协调
- 缺点:ID较大,人类不友好
25.2 领域模型的演进决策
处理重大变更的策略:
- 并行运行新旧模型
- 双写迁移
- 版本化API
- 增量替换
记录要点:
- 变更原因
- 迁移步骤
- 回滚计划
- 验证方法
26. 领域模型与持续交付
26.1 领域模型的CI/CD流水线
自动化测试与部署策略:
- 单元测试验证领域逻辑
- 集成测试验证持久化
- 契约测试验证服务边界
- 性能测试验证关键路径
yaml复制# 示例CI配置
steps:
- build: make
- test: make test
- integration: make integration_test
- deploy: make deploy_canary
26.2 领域模型的特性开关
逐步发布新领域逻辑:
cpp复制class OrderService {
public:
void placeOrder(OrderRequest request) {
if (features_.isEnabled("new-tax-calculation")) {
calculateTaxV2(request);
} else {
calculateTaxV1(request);
}
}
private:
FeatureFlags& features_;
};
实施建议:
- 开关应尽快移除
- 记录开关状态
- 监控不同路径
27. 领域模型与监控运维
27.1 领域健康指标
监控领域模型的关键指标:
cpp复制class OrderMonitor {
public:
void recordOrderPlaced(const Order& order) {
ordersPlaced_.inc();
orderValue_.record(order.total());
if (order.items().size() > 10) {
largeOrders_.inc();
}
}
private:
Counter ordersPlaced_;
Histogram orderValue_;
Counter largeOrders_;
};
监控重点:
- 关键业务流
- 异常情况
- 性能指标
27.2 领域事件的日志与追踪
分布式追踪领域操作:
cpp复制class OrderService {
public:
void placeOrder(OrderRequest request) {
auto span = tracer_->StartSpan("place_order");
span->SetTag("order_id", request.id());
try {
// 处理订单
span->Finish();
} catch (...) {
span->SetStatus("error");
span->Finish();
throw;
}
}
private:
Tracer* tracer_;
};
追踪策略:
- 关联跨服务调用
- 记录业务上下文
- 采样控制成本
28. 领域模型与安全考量
28.1 领域对象的安全边界
保护领域模型免受非法访问:
cpp复制class OrderRepository {
public:
std::optional<Order> findOrderForUser(OrderId id, UserId user) {
auto order = findOrder(id);
if (order && order->customerId() == user) {
return order;
}
return std::nullopt;
}
};
安全原则:
- 默认拒绝
- 最小权限
- 上下文检查
28.2 敏感数据的领域处理
安全处理支付信息等敏感数据:
cpp复制class PaymentProcessor {
public:
PaymentToken tokenize(CreditCard card) {
auto token = paymentGateway_.tokenize(card);
auditLog_.logTokenize(card.last4(), token);
return token;
}
private:
PaymentGateway& paymentGateway_;
AuditLog& auditLog_;
};
最佳实践:
- 避免存储敏感数据
- 使用专业支付处理器
- 审计关键操作
29. 领域模型与国际化
29.1 多语言领域错误消息
支持国际化的领域