领域驱动设计DDD

Eric Evans所著的《领域驱动设计》(Domain-Driven Design:通常简称为“DDD”)一书可以说是经典中的经典,虽然“领域”的概念早就存在,但是直到这本书的出现,才让人们真正开始认真审视软件的构建,相信你看了这本书后会真正体会领域的力量,也正是这个力量决定了软件最终的价值。

领域的含义:

简单的说,每个软件程序都会与其用户的活动或兴趣相关,其中使用程序的主要环境称为软件的“领域”。

领域中形形色色的业务逻辑构成了软件丰富多采的行为。举例来说,银行财务系统中,领域逻辑就包括了诸如开户,转帐等等操作。可能你会说,普通程序员很少会接触银行系统,这样的例子不够浅显,那我举一个更常见的例子,大凡程序员应该都接触过文章管理系统,它里面的置顶,加精等操作就是领域逻辑。这样看来,似乎用例对应的动作都是领域逻辑了,但是答案是否定了,比如说,文章管理系统中保存文章往往就不是领域逻辑,因为它只是一个和持久化相关的动作而已,是纯粹的技术实现,但是银行财务系统中的保存现金通常却被划为领域逻辑,因为它就是我们常说的存款,有明确的业务含义。看到这,似乎大家又有些Faint了,这里给出一个判断是否是领域逻辑的原则:就是这个逻辑动作是否有明确的业务上的含义,或者说是否是业务相关的,而不仅仅是技术相关的。

只有将技术实现手段从领域问题中剥离才能保证领域本身的精炼,保证程序员可以把精力集中到领域问题本身上来,而不会满脑子都是技术实现手段。

领域的组成:

按照Eric的表述,通常将领域中的组成角色分为以下五种:

实体(Entity):拥有唯一标识的对象。
值对象(Value Object):没有唯一标识的对象。
工厂(Factory):定义创建实体的方法。
仓储(Repository):管理实体的集合并封装其持久化过程。
服务(Service):实现不能指派或封装在一个单一对象上的操作。

领域的思考:

下面针对上面介绍的五种领域角色来逐一讨论。

实体的概念是比较好理解的,这样的例子很多,比如说每一个人都可以看作是一个“与众不同”的实体,我之所以用与众不同这个词是为了强调实体必须是能够唯一标识出来的,即便是在我们看作长得一模一样的双胞胎,他们也是能更根据一些标识来区分开,比如指纹,可能你会抬杠,要是没有手的残疾人怎么办?那样我们还可以使用DNA检测,当然,这些都是笑谈了,实际编程的时候,一般是使用一个自增数来作为标识,比如在MySQL数据库中保存实体的时候可以使用anto_increment属性的自增字段。需要注意的是如果想判断两个实体是否相等,不能根据实体的属性来判断,必须绝对依赖实体的标识,十年前的你和现在的你虽然在身高,体重,年龄等众多重要的属性中多或多或少的发生了变化,但你还是你,因为你的DNA不会因为这些属性的变化而变化,如果期间你的DNA发生的变异则属于意外情况,这里不考虑。这些理解起来似乎有些哲学的味道了。

值对象的含义,老实说相对实体来说比较模糊,很多人喜欢把数据传输对象也称为值对象(数据传输对象和我们这里说的值对象是有差别的)让人们对值对象的理解产生过很多歧义,而且值对象的例子不如实体那么直接。从字面上来理解,值对象没有唯一标识,大多数情况下,值对象是不变的,所以系统不用实时的跟踪他们,用的时候就实例化一个,不用的时候就销毁,但是,什么时候使用值对象?把哪些属性划为值对象?值对象的作用是什么?这些都是值得考虑的问题。通常来说,当我们进行领域建模的时候,优先把唯一标识和经常用来检索对象的信息作为实体的属性,而其他信息根据相关性或者划分到其他实体中,或者划分为值对象,举例来说:一个CMS系统中,对于文章实体而言,文章编号,文章标题等都应该作为文章实体的属性存在,而对于文章有效性期限的开始时间,结束时间两个信息则应该被放在一个独立的值对象中,这其中,只有开始时间或结束时间,或者开始时间和结束时间同时都存在或不存在,会代表不同的逻辑意义,合理使用值对象,既有利于屏蔽一些相关逻辑的复杂性,也可以保持实体对象的简洁。

工厂相对与前两者会好理解的多,毕竟从名字上就能体现出它的职责,那就是创建对象。既然是创建对象,那我们直接实例化一个不行么?简单的情况是可以的,但是工厂往往会带来巨大的好处,简单的说就是屏蔽了创建对象的复杂性。领域创建对象强调的关联,一组相关的对象应该被看作一个整体,对于其中任何对象的访问也应该从这个整体的“根”开始(通常整体中最重要的实体作为根),所以复杂的关联必然会使创建过程同样复杂起来,那我们可不可以在“根”实体的构造函数中完成对象的组装呢,简单的情况可以,复杂的不合适,比如说组装汽车,通常是在工厂里由组装工人和机器人来操作完成,如果我们在“根”的构造函数里完成组装,无异与在汽车里配备了组装工人和机器人,这当然是不必要的,汽车一旦组装出厂,就不需要组装工人和机器人了,此时再附带他们是一种累赘。

仓储的概念和一些人常说的数据访问对象(DAO)有些类似,但是并不等同,二者一个很大的不同是仓储有“根”的概念,而数据访问对象往往是按照数据库的表来划分的。使用仓储主要是为了查询和持久化领域对象,而领域对象之间往往会有复杂的聚合关系,为了保证不变量,所以才引入根的概念,对领域对象中某个子对象的访问必须通过根来导航。这样说可能不易理解,我举一个简单的例子:轿车,轮胎可以看成是一个领域对象的聚合,轿车是这个聚合的根,如果我们想访问轮胎,必须通过轿车的导航来进行,为什么如此规定,因为轿车和轮胎之间存在一个不变量:一个轿车有四个轮胎,如果允许客户端直接访问轮胎,那么就很难保证此逻辑不被破坏。

服务这个名词被用过很多次了,但是以前人们说的服务大多是从技术角度而言的,从分层来看属于应用层。一般是诸如注册成功发送一个邮件之类的东西,领域驱动设计中的服务不是这个范畴的概念,它强调的是实体之间的相互关系,而不是纯粹意义上的技术手段。举一个例子来说:CMS系统里,如果一篇文章被加入精华,则文章作者的经验值加一。此逻辑中涉及两个实体:文章实体和作者实体。经验值加一的逻辑不管是建立在文章实体里,还是作者实体里都显得冗余,所以有必要在实体之上在抽象出一个服务层来处理。这里可能有人会问:这样的逻辑我们放到传统意义上的应用层不行么?那样做不能说不行,但是多数情况不好,因为此逻辑属于领域逻辑,而不是应用逻辑,如果放在应用层,领域逻辑就外泄了,领域层也就成为了摆设,但是也有例外,有时候我们可能一时很难分辨一个逻辑是领域逻辑还是应用逻辑,这个时候把此逻辑加入到应用层是没有问题的,如果以后发现其作为领域逻辑更合适的话再重构不迟。

写完了回头看看,感觉只能称之为涂鸦心得,领域驱动设计更多要靠自己的体会。

领域驱动设计(Domain-Driven Design,简称 DDD)是一种专注于复杂业务场景的软件开发方法,其核心在于将业务逻辑与技术实现紧密结合,以应对软件系统的复杂性。DDD 提供了一套理论框架和实践模式,帮助开发者更好地理解、建模和实现业务需求。 ### 核心概念 1. **领域(Domain)** 领域是指软件系统所服务的业务范围或行业背景。在 DDD 中,领域是设计和开发的核心关注点,强调对业务规则和逻辑的深入理解。 2. **领域模型(Domain Model)** 领域模型是对业务规则的抽象表示,通常以对象模型的形式存在,包含实体(Entity)、值对象(Value Object)、聚合(Aggregate)、聚合根(Aggregate Root)等元素。 3. **限界上下文(Bounded Context)** 限界上下文用于明确领域模型的适用范围,确保模型在特定的边界内保持一致性和清晰性。它是解决模型冲突和保持模型完整性的关键机制。 4. **实体(Entity)** 实体是指具有唯一标识的对象,其身份在整个生命周期中保持不变,即使其属性发生变化。 5. **值对象(Value Object)** 值对象是没有唯一标识的对象,其等价性完全由其属性值决定。 6. **聚合(Aggregate)** 聚合是一组相关对象的集合,作为一个整体被操作,聚合根是聚合的入口点,负责维护聚合内部的一致性。 7. **领域服务(Domain Service)** 当某些业务逻辑不属于任何实体或值对象时,可以将其封装在领域服务中。例如: ```csharp public class SchoolDomainService { public void CreateSchool(School school) { // 执行创建学校的业务逻辑 } } ``` [^3] 8. **仓储(Repository)** 仓储用于管理聚合的持久化和检索,提供一种类似于集合的接口,使开发者可以专注于业务逻辑而不必关心数据存储细节。 9. **工厂(Factory)** 工厂负责创建复杂的对象或聚合,确保其初始状态的正确性。 ### 应用场景 DDD 特别适合于以下类型的项目: - **复杂业务逻辑**:当系统的业务规则复杂且需要长期维护时,DDD 提供了清晰的结构和职责划分。 - **产品化系统**:对于需要持续迭代和演进的产品,DDD 有助于保持代码的可维护性和扩展性。 - **多团队协作**:通过限界上下文的划分,不同团队可以在各自的上下文中独立工作,减少耦合。 相比之下,对于业务逻辑相对简单的系统,传统的 MVC 架构可能更为合适,因为它可以减少认知成本和开发成本。 ### 快速入门 1. **理解业务需求** 与业务专家紧密合作,深入理解业务规则和流程,形成统一的语言(Ubiquitous Language)。 2. **识别限界上下文** 通过上下文映射(Context Mapping)确定系统的不同部分及其交互方式。 3. **设计领域模型** 根据业务规则构建领域模型,明确实体、值对象、聚合等元素。 4. **实现领域逻辑** 使用领域服务、仓储、工厂等模式实现业务逻辑,确保技术实现与业务规则的一致性。 5. **持续演进** 随着业务的发展,不断调整和优化领域模型,保持系统的灵活性和可维护性。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值