news 2026/7/2 1:06:23

为什么要使用领域驱动设计?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
为什么要使用领域驱动设计?

这一说法是否自相矛盾呢?Martin Fowler在PoEAA一书中给了一个有力的解释:

我们把三层架构等除了领域驱动之外的架构方式都可以归纳为以数据为中心的架构方式,在图中是黑色的粗实线;

领域驱动设计在图中是绿色的粗实线。

  • 当软件在开发初期,以数据驱动的架构方式非常容易上手,但是随着业务的增长和项目的推进,软件开发和维护难度急剧升高。
  • 领域驱动设计则在项目初期就处在一个比较难以上手的位置,但是随着业务的增长和项目的推进,软件开发和维护难度平滑上升。

这幅图形象的解释了领域驱动设计和传统的软件架构模式两者在软件开发过程中解决复杂性之间的差异。

领域驱动设计的核心是什么?

顾名思义,领域驱动设计的核心是领域模型,这一方法论可以通俗的理解为先找到业务中的领域模型,以领域模型为中心驱动项目的开发。而领域模型的设计精髓在于面向对象分析,在于对事物的抽象能力,一个领域驱动架构师必然是一个面向对象分析的大师。

在面向对象编程中讲究封装,讲究设计低耦合,高内聚的类。而对于一个软件工程来讲,仅仅只靠类的设计是不够的,我们需要把紧密联系在一起的业务设计为一个领域模型,让领域模型内部隐藏一些细节,这样一来领域模型和领域模型之间的关系就会变得简单。这一思想有效的降低了复杂的业务之间千丝万缕的耦合关系。

下图为“以数据为中心的架构模式”,表和表之间关系错综复杂:

下图是“领域模型”:领域和领域之间只存在大粒度的接口和交互:

初期学习DDD的朋友一定不会错过Eric Evans写的《领域驱动设计:软件核心复杂性应对之道》,这本书名气很大,也是很多人入门领域驱动设计的首选读物,这本书提到了领域驱动设计中的一些概念:Repository,Domain,ValueObject等。但是初学者有可能得出一个错误的结论:有人误认为项目架构中加入***Repository,***Domain,***ValueObject就变成了DDD架构。如果没有悟出其精髓就在项目中加入这些概念,那充其量也不过是个三层架构;反之对于一个面向对象分析的高手而言,不使用这些概念也可以实现领域驱动设计。

以IUserRepository这样一个接口定义为例:

1

2

3

4

5

6

7

publicinterfaceIUserRepository : IRepository<User>

{

//What's this?

List<Rule> GetRules(int id);

//....

}

一个IUserRepository是一个Repository,他只能以User聚合根为单位进行操作。方法List<Rule> GetRules(int id)将此Repository打回了原形,这不再是一个Repository,这是一个DAL。

正确的实现方式:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

publicclassUser:AggregateRoot

{

privateList<Rule> GetRules()

{

returnnull;

}

publicvoid ApproveRequest(Request request)

{

varrules = user.GetRules();

//......

//如果有权限就批准

}

}

这段代码体现了User作为一个领域模型,他拥有自己的职责和能力。

如何开始实践领域驱动设计?

正如本文通篇所说,领域驱动设计讲究的是领域模型的分析和对事物的抽象,从来没有提起过数据如何存取这个话题,言下之意在领域驱动设计中,我们不关心过数据如何存取,怎么样写linq效率高,使用懒加载还是include,这些实现细节会将你带入传统的三层架构模式中。

在领域驱动设计中要先设计领域模型,接着写Domain逻辑,至于数据库,仅仅是用来存储数据的工具。使用database first那不叫领域驱动设计,很明显你先设计的表结构,所以应该叫数据库驱动设计更为准确。更不要引入数据库独有的技术,例如触发器,存储过程等。数据库除了存储数据外,其余一切逻辑都是Domain逻辑。

我们不妨以大家都比较熟悉的医院门诊看病流程举个例子,看看如何开始实践领域驱动设计:

我们暂且认为一个门诊看病流程就是一个完整的领域模型,此时你要忘掉数据库,不要再想表结构如何设计,而是就这一领域模型进行抽象:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

publicclassOutPatientProcess:AggregateRoot

{

publicRegistration _registration { get;privateset; }//挂号单

privateList<Examination> _examinations;

publicIReadOnlyList<Examination> Examinations => _examinations.AsReadOnly();//化验单

publicPrescription Prescription { get;privateset; }//处方

publicDateTime ConsultaionTime { get;privateset; }//接诊时间

publicDoctor Doctor { get;privateset; }//接诊医师

//开始一个门诊治疗过程

publicvoid StartProcess(Registration registration)

{

_registration = registration;

InquireSymptoms();

WriteOutExamination();

WritePrescription();

}

//询问病人病情

publicvoid InquireSymptoms()

{

}

//开立化验单

privatevoid WriteOutExamination()

{

_examinations.Add(newExamination());

}

//填写处方

privatevoid WritePrescription()

{

}

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 1:02:33

大模型推理优化三级体系:量化、投机采样与MoE稀疏激活的工程实践

引言&#xff1a;推理成本已成最大瓶颈 2026年&#xff0c;大模型推理成本已成为 AI 应用落地的最大瓶颈。一个百亿参数模型在 GPU 集群上的推理成本&#xff0c;可能占到总运营成本的 70% 以上。随着模型规模从百亿走向千亿、万亿&#xff0c;单纯依靠硬件升级已经无法覆盖成本…

作者头像 李华
网站建设 2026/7/2 0:59:18

如何3分钟掌握全网小说离线阅读:novel-downloader终极指南

如何3分钟掌握全网小说离线阅读&#xff1a;novel-downloader终极指南 【免费下载链接】novel-downloader 一个可扩展的通用型小说下载器。 项目地址: https://gitcode.com/gh_mirrors/no/novel-downloader 你是否曾为心爱的小说突然消失而心痛&#xff1f;是否在网络不…

作者头像 李华
网站建设 2026/7/1 23:59:48

移动端UI自动化测试框架Maestro终极指南:从入门到实战

1. 项目概述&#xff1a;为什么是Maestro&#xff1f; 如果你正在寻找一个能让你快速上手、告别繁琐配置、并且对移动端UI自动化测试真正友好的框架&#xff0c;那么Maestro很可能就是你一直在等的那个答案。我接触过Appium、Espresso、XCUITest&#xff0c;也折腾过各种基于图…

作者头像 李华