领域驱动设计是一种通过将实现连接到持续进化的模型来满足复杂需求的软件开发方法。领域模型是对业务模型的抽象,DDD是把业务模型翻译成系统架构设计的一种方式。
https://blog.csdn.net/baiye_xing/article/details/124081653
DDD与微服务的区别
DDD的核心诉求是将业务架构映射到系统架构上,在响应业务变化调整业务架构时,也随之变化系统架构。
微服务追求业务层面的复用,设计出来的系统架构和业务一致;在技术架构上则系统模块之间充分解耦,可以
自由地选择合适的技术架构,去中心化地治理技术和数据。
DDD的特点
根据业务模型设计系统:根据业务语义抽象梳理设计成领域模型,而不是通过数据库等数据源驱动设计。
数据模型统一:通过真实业务背景,梳理出业务域模型自然会形成出参、入参、中间临时属性收口统一为域模型。
业务模型与数据源无关:数据源更换,领域模型无感知,无须变更;一个域模型底层可能对应n个数据源;系统升级底层数据源结构改造时,变更对业务层是透明,域模型可无缝对接。
业务属性字段命名统一、引用唯一:MVC模式开发中,入参model/数据传输model/数据源model,同一个业务属性含义可能有多种不同的命名。
业务行为Action收口:原有开发模式下,一个Model类是一个POJO、DTO、DO,仅做数据传输,没有任何业务相关Action,属于典型的贫血模型。DDD中一个Model表述一个业务的域,有属性、业务行为Action,并且这个域的所有操作都在这个Model中,不仅有数据传输的作用也是一个具体的Service,是属于充血模型。这就可以做到业务操作高内聚、低耦合,系统更能直观体现业务逻辑。
DDD优缺点
优点:系统演进更方便,分为业务复杂性变化的演进和业务数据量变化的演进;更方便测试
缺点:系统改造成DDD复杂,开发熟悉DDD思想困难。
DDD适用场景
已经过了系统初期生长阶段,稳定运行一段时间,支撑的业务前景明朗,需要进行一定重构的
平台型业务系统,需要支持多类型、多租户、复杂功能的
研发众多,时常会有外部新研发进来开发的
核心包+插件化拓展的系统设计模式
为什么要用DDD
功能只是表象,模型才是内在
好的模型可以让功能实现更容易
DDD常见名词
贫血模型与充血模型
区别:
贫血模型的优缺点
优点1:很传统的编程思路,被许多程序员所掌握,许多教材采用的是这种模型,对于初学者,这种模型很自然,甚至被很多人认为是java中最正统的模型。
优点2:思路清晰,事务边界清晰一般来说service的每个方法都可以看成一个事务,因为通常Service的每个方法对应着一个用例
缺点:对象状态与行为分离,不能直观地描述领域对象。行为的设计主要考虑参数的输入和输出而非行为本身,不太具有面向对象设计的思考方式。
充血模型的优缺点
优点:贫血model偏重个性化,面向过程式。 充血偏共性化,采用OO设计,类拥有其属性及对应的行为,通过将职责分配到相应的模型对象或Service,可以很好的组织业务逻辑,因此非常适合于复杂的企业业务逻辑的实现,以及可复用程度比较高。
缺点1:领域驱动建模要求对领域模型完整而透彻的了解,只给出一个用例的实现步骤是无法得到领域模型的,这需要和领域专家的充分讨论。错误的领域模型对项目的危害非常之大,而实现一个好的领域模型非常困难。
缺点2:对象高度自洽的结果是不利于大规模团队分工协作。一个编程个体至少要完成一个完整业务逻辑的功能。对于单个完整业务逻辑,无法再细分下去了。
Model定义
Model(模型):承载着业务的属性和具体的行为,是业务表达的方式,是DDD的内核。是一个类中有属性、属性有Get/Set方法,并且业务的行为(Action)操作也是在模型类中(充血模型)即做业务逻辑处理,又做数据传输对象,模型分为Entity、Value Object、Service这三种类型
Model分类
Entity (实体)
有特定的标识,标识着这个Model在系统中全局唯一
内部值可以是变化的,可能存在生命周期 (比如订单对象,状态值是连续变化的)
有状态的Value Object
Value Object (值对象)
内部值是不变的,不存在生命周期 (比如地址对象不存在生命周期)
无状态对象
Service (服务)
无状态对象
当一个属性或行为放在Entity、Value Object中模棱两可或不合适的时候就需要以Service的形式来呈现
三种模型复杂度:Service > Entity > ValueObject,优先选择简单模型
生命周期
Factory (工厂):用来创建Model,以及帮助Repository (数据源)注入到Model中
Aggreagte (聚合根):封装Model,一个Mode中l可能包含其他Model(类似一个对象中包含其他对象的引用,实际概念更复杂)
聚合是用来封装真正的不变性,而不是简单的将对象组合在一起;
聚合应尽量设计的小;
聚合之间的关联通过ID,而不是对象引用;
聚合内强一致性,聚合之间最终一致性。
Repository (数据源):数据源的访问网关层、通过Repository来对接不同的数据源
边界--限界上下文
域的拆分
按业务抽象进行划分
一个业务拆分成几个独立的域,每个域又可细拆成不同子域
防腐
一个域在访问其他域的模型时,把获取到的模型做层转换映射到自己域的模型中(不直接使用别的域模型作为自己域模型中的一部分)
防止源域模型发生变更,依赖源域模型的调用方,在需要源域模型新功能时,必须要全局依赖修改,才在能兼容
防止域上下文不一致产生的冲突
限界上下文之间的映射关系
合作关系(Partnership):两个上下文紧密合作的关系,一荣俱荣,一损俱损。
共享内核(Shared Kernel):两个上下文依赖部分共享的模型。
客户方-供应方开发(Customer-Supplier Development):上下文之间有组织的上下游依赖。
遵奉者(Conformist):下游上下文只能盲目依赖上游上下文。
防腐层(Anticorruption Layer):一个上下文通过一些适配和转换与另一个上下文交互。
开放主机服务(Open Host Service):定义一种协议来让其他上下文来对本上下文进行访问。
发布语言(Published Language):通常与OHS一起使用,用于定义开放主机的协议。
大泥球(Big Ball of Mud):混杂在一起的上下文关系,边界不清晰。
另谋他路(SeparateWay):两个完全没有任何联系的上下文。
DDD架构设计
DDD架构 领域驱动设计没有特定的架构风格,它的核心是域模型驱动业务的思想,常见的领域驱动设计架构有传统的四层架构模式、事件驱动架构、CQRS架构、六边形架构等。
四层架构
User Interface为用户界面层(对外访问层API),负责向用户显示信息和解释用户命令。
Application为应用层,定义软件要完成的任务,并且指挥表达领域概念的对象来解决问题。
Domain为领域层(或模型层),负责表达业务概念,业务状态信息以及业务规则。
Infrastructure层为基础实施层,向其他层提供通用的技术能力。
基础设施层:基本上都是需要固化的代码,一次写成,需要变动的次数很少,一旦变动,就需要大量谨慎的回归测试。将所有的存储调用、中间件调用都沉淀在这一层中。
防腐层:对于一些基础的接口有二次包装或者不同的需求,就以XXXManager进行封装成防腐层,对于一些二方微服务系统的调用,也建议设置成一个防腐层XXXServiceManager进行防腐管理,这样也就可以灵活的在领域层进行二方领域的简单调用,避免过多外部领域逻辑的侵入了。
事件驱动
在服务层,对下层接口的协同有编排(Orchestration)和协调(Choreography)两种方式。
在编排中,服务控制器处理微服务之间的所有通信,并指导每个服务执行预期的功能。
在协调中,通过事件驱动的方式来协调微服务和函数。
事件驱动的三种模式
事件通知:系统发送事件消息以通知其他系统其域中的更改时;
事件推送:想要更新系统的客户端时;
事件溯源:对系统状态进行更改时,将该状态更改记录为一个事件,并且在未来的任何时间重新处理这些事件,从而自信地重建系统状态。