关于充血模型和贫血模型的讨论iteye上已经很多了,不是谁好谁坏的问题,都有适用的场景,业务复杂的当然可以使用充血模型,那些讨论几乎都是浪费口舌,也没说到点子上,讨论的话题应该是如何将业务逻辑合理分配到协作的多个对象上。和充血模型相关的是DDD领域驱动设计,其分层结构如下。
这里只关注充血模型中的职责分配,因为在设计开发中很容易在这方面出现问题,在充血模型中,一种最极端最常见的情况是将过多的业务逻辑不分青红皂白都放在领域对象中(Domain object),导致领域对象太臃肿,违反单一职责原则,很可能引起领域对象不稳定,它本来应该是比较稳定的,可在多个应用中重用。
在Java spring应用中之所以流行贫血模型的主要原因是领域对象(实体对象)一般是在spring容器之外创建的,例如主动new一个领域对象,或dao方法返回领域对象,或反序列化生成。通过这些方式创建的领域对象,其包含的依赖对象(如一些服务)是无法通过声明(例如通过@Autowired注解来声明或在xml配置中通过ref来声明)来自动注入到领域对象中的,需要领域对象自己创建依赖的对象实例,比较麻烦。这其实是误解,从spring2.0开始就支持将依赖的spring bean注入到领域对象中,即使领域对象是在spring容器之外创建的。Spring使用Configurable注解(注意不是Configuration注解)和AspectJ aop等来实现注入依赖对象到领域对象中,成为充血模型,这样充血领域对象就能和这些依赖的对象进行交互和协作来实现其领域逻辑,而不是贫血模型中将领域逻辑移到其他服务中。
OO设计原则(如单一职责等)和Craig Larman的GRASP(如信息专家)都是用来指导职责分配的,怎么这些在充血模型中就失效了,其实问题最终原因还是对这些原则没有真正掌握。
以处理用例(use case)中客户请求的层次结构为例,采用充血模型后,通常的交互层次是:client -》access service(接入层服务,面向各种客户端,提供多种形式的接入接口,如rpc、http/rest接口) - 》应用层服务(application service) -》领域层服务(domain service or domain object) -》 集成层(数据持久、基础设施服务) 。
access service提供面向客户端的接入服务,主要是接入层的请求路由、控制逻辑以及和具体客户端,用户类型相关的特殊逻辑,处理访问的认证鉴权、请求&响应的转化/格式化/消息打包解包,将访问路由到对应的application service,它尽量不要包含业务逻辑。在spring mvc中,access service体现为dispatch servlet+过滤拦截器。
从上面的描述可以看出,业务逻辑可以分布在应用层服务(application service)、领域层服务(domain service和domain object)、集成层/基础设施服务这3类之中,显然将过多的业务逻辑分配在领域对象(domain object)是不合理的。
对业务逻辑的分配,如果我们能明确其分配的具体原则,划分的边界,就可以做到合理分配。先前提到的OO原则是比较高层的通用的原则。
从服务化的思想看,DDD分层架构也是对服务类型的分类:应用服务application service、领域层服务(领域对象、领域服务domain service)、基础设施服务。
一个用例use case中包含很多业务逻辑和业务规则,哪些业务逻辑和业务规则放在领域层服务中,哪些放在应用服务中?哪些在基础设施服务中。也就是业务逻辑分配(划分)的标准是什么?这其中让很多人困惑,不好把握的是领域层(领域逻辑)和应用服务(应用逻辑)的划分标准,很多人只是口头上知道领域逻辑和应用逻辑,但要他具体讲解领域逻辑和应用逻辑如何划分,划分的标准是怎样的,几乎很少有人能说明白说透彻,模棱两可,没有可操作性。下面讲解服务的分类以及领域逻辑和应用逻辑的具有可操作性的区别和划分标准,区别见下面的黑体字所描述的部分,知道了可操作性的区别,划分标准也就真的清楚了。
- 显然领域对象负责的是领域逻辑,退回到领域逻辑的概念定义上来,领域逻辑应该是该领域对象专有的逻辑,它是不随应用、用例、客户端而改变的,和应用、用例、客户端无关。例如对某领域中的身份证领域对象,其身份证的验证规则是不变的,身份证总是18位,不管是在哪个应用中,还是哪个用例中,该规则都不变,那很显然这个规则就是身份证领域对象的领域逻辑。再比喻,在银行账号中,如果规定取款金额必须小于余额,这个逻辑不管你的取款流程是什么,不管是银行的哪个应用,这个逻辑都保持不变,那这个就是账号的领域逻辑。可见这也是符合信息专家原则的。如何判断逻辑是不是该领域对象专有的,去问领域专家,他对业务是最清楚的,领域模型其实应该是他负责建模的。
- 领域服务(domain service),这个也类似领域对象,也就是它的领域逻辑是不随应用、用例、客户端而改变,是该领域专有的,只是其领域逻辑要跨多个领域对象,例如银行转账,涉及到两个领域对象。它一般是起协调或控制作用,对应设计模式中的facade模式。
- 应用服务(application service),划分好了上面两个的职责,这个就比较简单了,剩下的逻辑就基本属于应用逻辑(不管展示层逻辑)。相比而言,应用逻辑(应用服务)是最不稳定的,因为它是每个应用专有的,一般不能在其他应用中重用。例如某用例中,需要发送短信通知,通常这个不属于领域对象和领域服务,只能是应用逻辑。对复杂的应用服务,也可采用facade模式对领域层服务进行服务编排。
- 基础设施服务/公共服务,例如集成服务、中间件、治理层、数据访问/数据持久服务、消息服务、短信基础服务。
综上所述,是否公共共享重用、相对稳定不变才是划分业务逻辑到领域层和应用层的标准,此外领域层也可能较薄,应用层可能厚。
领域层服务比较稳定,可以在多个应用中重用,也就是领域对象和领域服务可被多个上层应用的应用服务共享,应用服务是领域服务和领域对象的宿主环境和运行容器,也就是应用服务包装/调用领域服务和领域对象。 如果我们用服务化框架将领域服务和领域对象的能力开放出去,就是我们通常称呼的各种XX中心,例如订单中心、用户中心。
相关推荐
(1)每一个数据库表对应创建一个类,类的每一个对象实例对应于数据库中表 (2)领域对象同事封装了业务逻辑 (3)领域对象同时负责数据持久化,在其中封装对数据库的
一、失血模型 失血模型简单来说,就是domain object只有属性的getter/setter方法的纯数据类,所有的业务逻辑完全由business object来完成(又称TransactionScript),这种模型下的domain object被Martin Fowler称之...
NULL 博文链接:https://melin.iteye.com/blog/716507
本文解释了当今比较新的设计模式中的贫血和充血模式。对加深理解二模型很有帮助!
基于GO的六边形架构框架,可支撑充血的领域模型范式代码实现
微服务架构首先要关注的不是RPC/ServiceDiscovery/Circuit Breaker这些概念,也不是Eureka/Docker/SpringCloud/Zipkin这些技术框架,而是服务的边界、职责划分,划分错误就会陷入大量的服务...• 充血模型 • 事件驱动
1. 充值 2. 支付 3. 提现 4. 查询余额 5. 查询交易流水
贫血模型or领域模型的举例对比,让你初步了解贫血模型与领域模型的区别和概念。附加一个自己创建的代码范例
领域模型的职责是实现业务逻辑,如果领域模型只是用来处理简单的逻辑(比如贫血模型),那么领域模型的作用微乎其微,甚至可以忽略,数据转换的成本比领域模型带来的好处还多,这种情况其实就是在原有的分层架构中...
欢迎大家发表自己的看法,希望朋友知无不言,言无不尽.
火龙果软件工程技术中心 对于领域模型这个概念,以前没有系统性的认识,只是根据经验,在设计系统时自发的在使用....domainobject3、充血模型Service(事务封装)--->domainobject<--->DAO4、胀血模
第一点原因是,大部分情况下,我们开发的系统业务可能都比较简单,简单到就是基于 第二点原因是,充血模型的设计要比贫血模型更加有难度 第三点原因是,思维已固化,转型
体会下充血模型开发微信钱包系统 聚合和聚合根是什么? 领域事件是什么? 看看领域事件的本质(解耦,异步,削峰) 工厂和资源库的作用? 领域服务是什么? 通过用例分析法和领域事件梳理电商购物车核心流程 第4章 DDD...
充血性心力衰竭急诊治疗.ppt
充血性心力衰竭的急诊治疗.pptx
充血性心力衰竭急诊治疗剖析.ppt
自由DDD框架自由是一个基于六边形架构的框架,可以支撑充血的领域模型范式。总览集成虹膜HTTP / H2C服务器和客户端集成普罗米修斯AOP工作者和无侵入上下文可扩展组件依赖注入&依赖倒置&开闭原则DDD和六边形架构...
背景:充血性心力衰竭的危险因素之一仍在研究中,是高尿酸血症。 它是独立的危险因素还是仅仅是与心血管疾病有关的其他疾病(如高血压,糖尿病和血脂异常)的结果,仍然值得商bat。 目的:我们的研究目的是阐明心力...
食管黏膜恶性平坦型充血性病变.docx