C++中的领域驱动设计:复杂项目的架构

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

为什么DDD不是枯燥的图表,而是鲜活的架构

\n

当C++项目规模超出“玩具级”应用时,开发者常常面临混乱:业务逻辑分散在控制器中,数据库决定类结构,新手不敢触碰遗留代码。领域驱动设计(DDD)不是一套抽象规则,而是帮助驾驭复杂性的实用工具。在本文中,我们将通过具体代码示例,探讨如何在C++中引入DDD,以及为什么它能拯救你的项目免于变成“大泥球”。

\n\n

什么是DDD,C++开发者为何需要它?

\n

领域驱动设计是一种以领域模型为核心、而非技术细节为重点的方法。在C++中尤其重要:该语言提供了强大的工具(模板、RAII、智能指针),但如果没有正确的架构,项目就会变成单体,修改一个功能就会破坏一切。

\n

DDD提供两个层次:

\n
    \n
  • 战略建模:将系统划分为多个上下文(Bounded Contexts)并配置它们之间的交互。
  • \n
  • 战术建模:构建块——实体(Entity)、值对象(Value Object)、聚合(Aggregate)、仓储(Repository)、领域服务(Domain Service)。
  • \n
\n

我们将重点放在战术建模上,因为它为C++代码提供了具体的模式。

\n\n

分层架构:C++中DDD的基础

\n

DDD要求清晰的层次划分。C++项目的典型结构如下:

\n
    \n
  • 领域层(核心):实体、值对象、聚合、领域服务。不依赖任何框架或外部库。
  • \n
  • 应用层:用例(use cases)、编排。仅依赖领域层。
  • \n
  • 基础设施层:仓储实现(SQL、Redis、文件)、与外部API交互。实现领域层中的接口。
  • \n
  • 表示层:用户界面(控制台、REST API、GUI)。
  • \n
\n

这不是硬性规则,而是建议。关键是依赖方向向内:外层可以依赖内层,反之则不行。

\n\n

示例:错误做法

\n
// ❌ 糟糕:业务逻辑与SQL混在一起\nclass UserController {\n    void createUser(const std::string& name) {\n        // SQL查询直接写在这里\n        db.execute("INSERT INTO users (name) VALUES (?)", name);\n        // 验证逻辑也在这里\n        if (name.empty()) throw std::runtime_error("Name required");\n    }\n};\n
\n\n

示例:DDD风格

\n
// ✅ 良好:清晰分离\nclass User : public Entity<User, int> {\n    std::string name_;\npublic:\n    explicit User(int id, std::string name) : Entity(id), name_(std::move(name)) {\n        if (name_.empty()) throw std::invalid_argument("User name cannot be empty");\n    }\n    const std::string& name() const { return name_; }\n};\n\n// 仓储接口(领域层)\nclass IUserRepository {\npublic:\n    virtual ~IUserRepository() = default;\n    virtual void save(const User& user) = 0;\n};\n\n// 实现(基础设施层)\nclass SqlUserRepository : public IUserRepository {\n    void save(const User& user) override {\n        // 仅SQL,无业务逻辑\n    }\n};\n
\n\n

C++中的DDD构建块

\n\n

实体(Entity)

\n

这是具有唯一标识符的对象,该标识符随时间保持不变。在C++中,可以方便地创建一个基础模板类:

\n
template<typename T, typename IdType>\nclass Entity {\n    IdType id_;\npublic:\n    explicit Entity(IdType id) : id_(std::move(id)) {}\n    IdType id() const { return id_; }\n    bool operator==(const Entity& other) const { return id_ == other.id_; }\n                

博客

书籍推荐