领域驱动建模(EvansDDD)课件.ppt

上传人(卖家):晟晟文业 文档编号:4565987 上传时间:2022-12-19 格式:PPT 页数:70 大小:2.75MB
下载 相关 举报
领域驱动建模(EvansDDD)课件.ppt_第1页
第1页 / 共70页
领域驱动建模(EvansDDD)课件.ppt_第2页
第2页 / 共70页
领域驱动建模(EvansDDD)课件.ppt_第3页
第3页 / 共70页
领域驱动建模(EvansDDD)课件.ppt_第4页
第4页 / 共70页
领域驱动建模(EvansDDD)课件.ppt_第5页
第5页 / 共70页
点击查看更多>>
资源描述

1、领域驱动建模(Evans DDD)Evans DDD 2004年Eric Evans 发表Domain-Driven Design Tackling Complexity in the Heart of Software(领域驱动设计)简称Evans DDD 领域建模是一种艺术的技术,它是用来解决复杂软件快速应付变化的解决之道 Evans DDD领域模型重要性 没有领域模型,只是靠代码编写完成一个又一个功能,复杂的领域需求会使得他们无法交流讨论,使工作陷入泥沼。有少许领域模型,但是没有维护好模型与代码直接的联系,两者产生差异,无法实现。DDD优点分析设计发展的三个阶段 第一阶段:围绕数据库的驱

2、动设计,新项目总是从设计数据库及其字段开始。第二层次:面向对象的分析设计方法诞生后,有了专门的分析和设计阶段之分,分析阶段和设计阶段是断裂的。第三阶段:融合了分析阶段和设计阶段的领域驱动设计(Evans:DDD)。第一阶段:传统的数据库方式 过去软件系统分析设计总是从数据库开始,这种围绕数据库分析设计的缺点非常明显:1.分析方面:不能迅速有效全面分析需求。2.设计方面:导致过程化设计编程,丧失了面向对象设计的优点。2.运行方面:导致软件运行时负载集中在数据库端,系统性能难于扩展,闲置了中间件J2EE服务器处理性能。对象和关系数据库存在阻抗,本身是矛盾竞争的。第二阶段:分析和设计分裂 第二阶段比

3、第一阶段进步很多,开始采取面向对象的方法来分析设计需求。分析人员的职责:是负责从需求领域中收集基本概念。面向需求。设计人员的职责:必须指明一组能北项目中适应编程工具构造的组件,这些组件必须能够在目标环境中有效执行,并能够正确解决应用程序出现的问题 两个阶段目标不一致,导致分裂,项目失败。新阶段:分析设计统一语言 统一领域模型,它同时满足分析原型和软件设计,如果一个模型实现时不实用,重新寻找新模型。一个无处不在(ubiquitous)的语言,项目中所有人统一交流的语言。减少沟通疑惑,减少传达走样。使得软件更加适合需求。没有领域(边界)的模型 一个印在大纸张上的完整类图,整面墙都被它覆盖,花几个月

4、分析开发的领域模型,模型大多数对象都与其中三四个对象有错综复杂的关系,且关系网几乎没有自然边界。分析人员是忠于领域需求本质。问题:开发人员开始实现应用程序时,彼此纠缠的关系根本无法转换成可存储 可检索的实现。是不是基于概念的模型类图不能成为程序设计的基础?领域模型在软件架构中位置什么是领域模型 Domain Model?某个范围内的模型。首先是边界划分,在边界中寻找代表领域本质旋律的模型。领域模型只表达需求真实世界模型,和软件架构技术无关。模型都是有前提和范围,或者称为有场景前提的。没有跨越范围的永恒不变的模型。由领域专家来定义领域模型。名词=类名 动词=类中方法 服务或其他机器人机器人的领域

5、模型确定核心领域 大型系统中,有很多有用的组件,他们非常复杂,都是软件成功不可或缺的,这样组件实在太多,以至于领域模型的精髓部分变得不明显甚至被忽视。不可能所有部分都进行提炼,分清轻重缓急,让领域模型真正成为资产。核心模型必须足够灵活和充分平衡来创建应用程序功能,不要倾向于使用技术基础结构如数据库来解决问题。无需专业业务知识容易能理解能引起程序员的兴趣,他们认为只有解决这些问题才能积累自己专业知识,同时为自己简历增光添彩,这对于公司是浪费。不注重核心领域的案例 银团贷款系统:大多数技术天才和技术高手都对数据库映射层和消息接口津津乐道,而业务模型却交给一些刚刚涉足面向对象技术的新手们打理。尽管为

6、持久领域对象提供详细注解文字说明,能够反映设计思路,也设计了友好的用户界面。这些特性都是外围,当这个软件最终交付用户使用时,差劲程序员二次开发拓展时却依然搞得一塌糊涂,整个项目差点失败。通用子域:非核心领域 提炼核心领域,就必须剔除反面通用子域。不同行业运输业 银行业 制造业都需要某种形式组织结构图。组织结构图就是通用子域。许多应用跟踪应收帐款 费用分类和其他帐务信息,这些信息都可以使用通用的会计财务系统来处理。有两个项目处理带时区功能的日期和时间组件,花费最好的程序员数周时间,虽然必须做,但不是系统核心。考虑现有解决方案或开源公开模型来替代通用子域。考虑外包,将通用子域外包,自己掌握核心领域

7、。领域中寻找核心模型 找出核心模型,提供一种方法让我们很容易地从众多支持模型中将它区分出来,将最有价值 最体现专门知识的概念凸显出来,核心变小。让最好的程序员来处理核心模型,根据需要调整人员的配备,尽力找出核心的深层模型,对于其他部分投入必须经过考虑,是否能为提炼出来的核心提供支持。模型的特征 模型表达的“是什么”,是战略方向性,而不是”怎么做”等技术细节。设计中产生了一大堆用来实现算法 解决问题的方法,而描述这个问题的方法变得模糊不清。怎么做的方法在模型中泛滥成灾,表明模型存在某种问题。算法或计算非常复杂,导致设计受到了冲击,模型中的概念变成了用“怎么做”来解释,而不是用“是什么”表达。内聚

8、 物体之所以成为物体,是因为其内聚机制。内聚也就是一种组合组成关系,某个物体由哪些部分组成,或者说由这些部分内聚聚合在一起。通过内聚方式来切分领域,切分模型,寻找核心模型。算法计算机制本身存在内聚性,使用策略模式等框架把这些内聚计算分离出来,用一个明确接口来说明这个框架的功能,将怎么做复杂细节交给框架去完成。领域模型切割 1.将复杂大的领域分割成子领域。2.抓住子领域的核心,建立核心模型。3.对核心模型实现灵活性细节设计旁门左道的快速开发 没有分层架构的快速开发基本是旁门左道,不如返回Foxpro和Delphi/VB两层时代。将本属于业务层的逻辑交由表现层来处理的快速UI方式也是一种旁门左道。

9、快速开发必须基于良好的质量,虽然良好的分层架构带来开发效率的降低,但是这些也是可以有方法解决。模型元素 实体(Entity)A thread of continuity and identity.在时间上一系列连续性(continuity)和标识(identityID)来定义。值对象(Value Object):如果一个对象代表了领域的某种描述性特征,且没有概念性的标识。Description原型。服务(Service):行为接口。实体 实体就是在客观世界中有实体内容的物体对象。经过时间延续一直保持其特点不变。软件实际是客观世界的拷贝或镜子,实体就是镜子中那个实物。必须拥有自己的唯一ID,主键

10、,如果没有一个ID标识,为每个实例加上一个具有唯一性ID,可能是内部使用。由于对象主观认定性,在特殊情况下,我们可能会主观划分一些实体。实体建模 实体最基本职责是保证连续性,以便使之有清晰 可预见的行为。关注重点不是它们的属性或行为,而是找出固有的特征,提出其他细节。这个固有特征包括:可以唯一标识对象的 特征;经常用来查找或匹配对象的特征。只留下和特征相关的行为和属性,其他则转移到与该实体相关联的其他对象。目的:保持实体高度精简。特征核心值对象 许多对象没有标识,只是事物的某些性质描述。四色原型中的蓝色des直接对应值对象。将所有对象都加上标识,会影响系统的性能,增加复杂性,使所有对象看上去都

11、是一个模式,混乱。只关心what,不关心who 或 which,只关心对象是什么?如果有多个这样对象排列在一起,我们不用去分辨它们。只关心what:有两只相同颜色和粗细的笔,随便拿一个都可以画画。地址值对象 邮购软件中的地址是值对象:用地址作为发货目的地。如果住在一起多个室友邮购,不影响邮递,有名字作为标识。邮政软件中的地址是实体:将地区分层次结构,区 城市 街道 邮编 个人地址。电力运营软件中地址是实体:如果住在一起多个室友申请电力服务,电力公司必须区分。值对象和实体是整体值对象设计 由于不关心软件运行时使用的是值对象的哪个实例,没有了分辨拘束,可提升性能和优化。值对象复制性:两个人具有相同

12、名字,表示名字的值对象可以互换复制,不会使他们成为一个人。值对象共享性:两个Person对象不需要自己各自的Name值对象,可以共用一个Name值对象。值对象不变性:值对象属于实体,当实体把它的值对象传递给其他对象时,如果其他对象对这个传过来的值对象修改不当,就会破坏其所有者的不变性约束,从而破坏它的所有者实体对象。值对象共享 值对象非常巨大,每个电源插座都是一个值对象,一个房子有上百个插座对象,由于值对象可以互换 共享,只使用一个插座实例就可以。Flyweight模式:避免大量拥有相同内容的小类的开销(如耗费内存),使大家共享一个类(元类)。不适用于实体。值对象复制 Prototype模式允

13、许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节。Java的clone也是一种复制。复制产生大量对象会阻塞系统,但适合在分布式系统中,相反,使用共享,会降低性能;高并发系统中,复制减少锁处理,共享需要精妙的锁处理技巧。实体和值对象区分 区分实体和值对象有助于我们在分析需求时抓住重点(实体),有主次之分,纲举目张。由于关注重点不同,就会对值对象定义不同。消费拿起一瓶牛奶喝,这时我们关注的是他喝牛奶之外一些重点,至于选择哪个牛奶瓶不是我们关注重点,随便哪一个都行,这是值对象。对于牛奶生产商而言,每瓶牛奶都很重要,生产日期有效期等等,因此,这里牛奶瓶就成了实体。实体之间关系 高内

14、聚低关联是设计基本原则。是重构的准则。找出关联是细分模型的一种方式,从而更恰当地定义模型边界。关联不是手头任务本质或不能反映模型对象基本含义,完全取消它。少用双向关联,除非技术性能要求。模型中关联越少、越简单越好。完全摆脱数据库影子,SQL语句作为规则封装在模型中。聚合Aggregate 一个聚合是一簇相关联的对象,出于数据变化的目的,将这些对象视为一个单元。每个聚合都有一个根和一个边界。边界定义了聚合中应该包含什么。根是包含在聚合中的单个特定实体。根是聚合中唯一允许被外部引用的元素,在聚合边界内,对象之间可以相互引用。实际就是整体和部分的关系。轿车根聚合中的不变性 不变性Invariants

15、定义:无论何时数据发生变化,都必须满足所有一致变化的规则,俗话:同生死。聚合内部的不变量必须在每次事务完成时满足。这可有仓储来实现。一些依赖关系只能在某些特定的时刻 通过事件借助有事务支持的服务来完成,或通过线程安全模式实现原子操作。如何做到不变性 根实体具有全局标识,并最终负责对不变量的检查。根实体有全局标识,而边界之内实体有本地标识,这些标识仅在聚合内部是唯一的。聚合边界外任何对象除了可以引用根实体,不能持有任何对其内部对象的引用。根实体可以把内部其他实体引用传递给其他对象,只能临时使用。根实体可以复制内部一个值对象实例副本给外部另外一个对象,副本再也与聚合无关系了。CRUD中不变性约束

16、通过数据库查询直接获得的对象只有聚合的根,其他所有聚合内对象可以通过聚合关系找到,性能上可采取懒加载防止大对象。删除必须一次性删除聚合边界内所有对象。当在聚合边界内发生的任何对象修改被提交时,整个聚合的所有不变量必须被满足,也就是统一修改。聚合根和不变性采购订单订单不变量约束 所以采购单项的金额之和不得超过采购单的最高限额。不变量保证:当加入新子项时,PO对总金额检查,如果不对,把自己标记非法,不好。变更管理:删除PO时,子项同时删除,但是它们关联关系何时终止,模型没有指示。不同时间修改商品价格会造成哪些影响无法评估。并发共享:如何解决多个用户同时修改一个PO?并发锁粒度 如果多个用户同时修改

17、一个PO,我们必须对这个PO实例锁定,以让某个时刻只能一个用户修改。通过数据库锁机制或者使用线程锁机制实现,关键是锁PO整个实例带来问题,这种锁排他性的,就无法允许其他用户也许对PO其他部分进行访问,性能差。更改模型,根据修改频繁程度单独列出一个对象,比如Price经常修改,就成为Price对象,锁定Price这个小对象,无需锁定整个PO。新订单模型不变性的实现方式 在生命周期中维护对象的完整性。避免模型由于管理生命周期的复杂性而陷入困境。三个模式来处理:1.聚合(Aggregate):定义清晰的所有权和边界使模型更加紧凑,避免出现盘根错节的对象关系网。聚合圈出一个范围,在这个范围中,对象无论

18、在哪个生命周期,保持不变性。2.工厂(Factory)3.仓储(Respository)生命周期之始,使用工厂和组合提供了访问和控制模型对象的方法生命周期边界和管理 聚合圈出一个范围如前图中红线,在这个范围中,对象无论在哪个生命周期,保持不变性。也就是子对象和父对象的生命周期是一致不变的。建立聚合的模型,并且把工厂和组合加入设计中来,可以使我们系统地对模型对象生命周期进行管理。生命周期之始,使用工厂和Repository提供了访问和控制模型对象的方法。工厂 生命周期管理具有复杂的职责,如果让一个复杂对象来负责自身的创建工作,会由于职责过载产生问题,人不能拎着自己头发拔高,孙猴子也是从石头缝里出

19、来的,不是从自己身体钻出来的。复杂对象的创建和组装应该由单独工厂实现,也就是工厂模式。将对象创建和使用分离。工厂属于领域层,工厂把聚合作为一个整体创建出来,创建方法必须是原子的,保证其不变量得到满足。专门工厂创建聚合 如果聚合根需要一个工厂创建,又不适合充当工厂,也就是没有一个自然地方容纳工厂,那么就创建一个专门的工厂对象或服务。Repository由来 数据库只是对象的永久保存方式,就象我们打字时经常需要存盘一样,我们不能因为要“存盘”而去关心“存盘文件格式(数据表结构)”。我们应该更聚焦在模型这个对象,把所有对象的保存(冬眠)和调用(激活)交由Respository完成。对象保存到数据库交

20、由专门的Repository仓储来完成,由Repository负责如何将对象分解成数据库能够保存的格式。Repository和查询不需要为通过导航方法能够获得持久对象提供查询访问,聚合内部对象可以通过根来导航。值对象无需全局查询获得,比较少见,值对象生命周期很短,属于临时对象,一般通过聚合根获得。仓储可以实现数据库新增 修改 删除和查询CRUD,仓储可以实现不同标准的各种查询。Repository和工厂Repository定义 为客户端访问某一聚合类对象提供全局访问接口Repository,Repository主要是在内存中建立一系列的聚合对象。Repository提供CRUD等通用对象操作方

21、法,把数据库数据存储插入和删除等方法封装起来。但是不插手事务。提供符合对象方式筛选查询,仅为确实需要直接访问的聚合根提供仓储,其他则不必。让客户端只关心模型,而不是数据存储。存储和访问都交给Repository完成。仓储统一语言 忽视持久化InfrastructureUIDomainData AccessApplication/Service查询仓储Specification模式 查询存在大量项目,但必须是围绕实体聚合根对象的查询,可以使用专门框架。引入Specification制定,用来让客户端将它希望获得的查询结果描述出来,也就是制定出来。输入参数使用Criteria来封装各种查询输入参数

22、,提供Criteria的查询框架比较复杂,如Hibernate的Criteria。如果聚合中有大数据,可通过懒加载lazy延迟加载,只返回一个代理,使用时,再进行加载。Specification模式 业务规则不适合放入实体和值对象,规则的变化和组合会很多,包括各种算法或者条件判断,这些会掩盖领域对象的基本含义,这些就放入专门对象Specification中。Specification表示业务规则,有指定要求的意思。Specification类似围绕实体的值对象。第三种模型 服务 将行为放入对象才是真正对象,这样可防止面向过程编程。但是放入不确当行为,会破坏对象的清晰概念。有些对象侧重于操作动作

23、行为,没有状态,就象四色图中MI,是一种活动事件,这些对象应该被标记为服务。服务来源现实:加油服务 快递服务,服务不是一个过程化编程的概念。分应用服务(事务安全)和领域服务。服务类型 领域层服务:与业务有关,需要协调多个实体完成的功能,比如资金转账;帖子CRUD;CashSales;下订单等。应用层服务:与软件设计有关的,在业务领域中没有实际意义的行为活动,比如两个业务系统的接口;实体和值对象由于过于细化松耦合,就无法提供一个访问自身领域层的方便入口,这时需要应用服务。类似MVC中Controller职责。基础层服务:比如发送Email,打印输出等等,。实体和行为操作的问题 将业务行为都使用服

24、务实现,实体中除了setter/getter方法以外,就没有任何实质业务行为,这是贫血失血模型。如果将所有行为操作都塞入实体对象,那么实体对象变得非常庞大臃肿,失去灵活性。有很多行为操作无法被封装进实体,但是又涉及多个实体,呈现面向函数式特点(function)。职责驱动开发 面向对象设计方法很多,但是很少有关注行为过程。roles-and-responsibilities模型:对象扮演不同角色,实现不同职责。把应用的职责切分到接口中成为其方法。然后实现职责行为之间的交互。用接口实现职责,一个实体实现不同职责的接口。什么是职责 定义:对象执行的动作;对象包含的知识:算法 约束 规格 描述;当前

25、对象影响其他对象的主要因素。特征:知道knowing什么;做 doing什么;决定deciding什么。构造invention、约束表达、规格Specification和描述Description都可以成为职责。分配职责 将职责分配给对象,使得对象有形有态。按照高凝聚原则分配。遵循假设:“如果没有这个职责,会怎样”。如果发现职责太广泛,不能分配到单个对象中,那么就切分职责,由这些小职责组合成更大职责。职责实现一个对象能够扮演多个角色使用方法行为来实现职责。不同角色有不同方法,如何解决这个矛盾?DCI架构 数据Data:领域模型。场景Context:领域模型活动存在的场景,或者前提条件。交互In

26、teractions:模型在特定场景下以某种角色活动的行为操作。不同角色有不同的交互。DCI架构和服务StatelessContextpublic class ForecastingContext implements ForecastingContextLocal/*an asynchrounous method for determining the energy requirements of the given trip.*/Asynchronous public Future forecastEnergyRequired(Trip trip)BehaviourInjector bi=

27、new BehaviourInjector(this);/场景将实体对象下塑为角色,开始交互行为 DCI典型调用方式EnergyConciousTrip t=bi.assignRole(trip,EnergyConciousTrip.class);double energy=t.forecastEnergyRequirements();return new AsyncResult(energy);Domain Events领域事件 领域事件是在不同场景下由实体发出事件驱动服务,通过类似异步消息机制实现松耦合。场景隐含,事件代表场景出头牵线。DCI架构是主动将功能实现的参与者(数据模型 角色和行

28、为 场景)进行动态组合。领域时间和DCI架构都将薄化服务模型,减少服务模型臃肿的现象(或者MVC的控制器)。Domain EventsDownload SourceDomain Events 工作原理Domain Model ModelListernerComponentJava concurrent FutureDomain MessagePool.run开源框架JdonFramework提供DE机制http:/ Query Responsibility Segregation)读写分离;更加伸缩:(1)写=Commands命令=主要是改变模型状态,无返回结果。(2)读=Queries查询=纯粹读取,不改变任何模型状态。使用基于Domain Events的EDA架构(Event-Driven Architecture)。可扩展至消息或异步系统。CQRS(命令查询分离)架构User interfaceServiceDomainEvent/Message BUSInfrastructureQuery/ReportingCommandsCommandsEvents更多资料和资源 DDD领域驱动设计:http:/ CQRS架构:http:/ DCI架构:http:/ DDD开放源码案例系统JiveJdon:http:/

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 办公、行业 > 各类PPT课件(模板)
版权提示 | 免责声明

1,本文(领域驱动建模(EvansDDD)课件.ppt)为本站会员(晟晟文业)主动上传,163文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。
2,用户下载本文档,所消耗的文币(积分)将全额增加到上传者的账号。
3, 若此文所含内容侵犯了您的版权或隐私,请立即通知163文库(发送邮件至3464097650@qq.com或直接QQ联系客服),我们立即给予删除!


侵权处理QQ:3464097650--上传资料QQ:3464097650

【声明】本站为“文档C2C交易模式”,即用户上传的文档直接卖给(下载)用户,本站只是网络空间服务平台,本站所有原创文档下载所得归上传人所有,如您发现上传作品侵犯了您的版权,请立刻联系我们并提供证据,我们将在3个工作日内予以改正。


163文库-Www.163Wenku.Com |网站地图|