`
顽石
  • 浏览: 167093 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

充血模型中的职责分配

 
阅读更多

关于充血模型和贫血模型的讨论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中心,例如订单中心、用户中心。 

     

      

  • 大小: 65.4 KB
分享到:
评论

相关推荐

    充血模型设想实现(2010/07/30更新)

    充血模型,也被称为“Rich Domain Model”,是领域驱动设计(DDD)中的一种核心概念。在软件开发中,领域模型是对业务领域的抽象和建模,它包含业务规则、逻辑和状态。充血模型强调对象应该拥有自己的行为和状态,而...

    浅谈Asp.net中使用“充血模型”1

    在Asp.net开发中,"充血模型"是一种提倡领域对象拥有丰富行为和业务逻辑的设计模式,相对应于传统的"贫血模型"。"贫血模型"通常将数据模型、业务逻辑和数据访问分离,使得领域对象仅包含属性,而业务逻辑和数据操作...

    对贫血和充血模型的理解

    特别是在面向对象编程中,贫血模型(Anemic Domain Model)和充血模型(Rich Domain Model)两种设计策略,一直被广泛讨论和应用。它们代表了不同的业务逻辑和数据关系处理方式,对系统的架构和后续维护工作有着深远...

    失血贫血充血胀血模型.docx

    胀血模型是对充血模型的一种扩展,领域对象不仅包含业务逻辑,还可能包含基础设施相关的代码,如数据访问代码。这种模型可能导致对象过于庞大,不易维护。 优点: 1. 自包含:领域对象能自我处理所有事务,无需依赖...

    基于GO的六边形架构框架,可支撑充血的领域模型范式代码实现.rar

    然而,在充血模型中,领域对象不仅包含了数据,还封装了大量的业务逻辑。这种方法使得领域模型更加生动且有力量,因为它们可以直接执行复杂的业务规则,降低了对额外服务层的依赖,提高了代码的可读性和可维护性。 ...

    基于六边形架构的充血领域模型设计源码——Freedom框架

    该项目为Freedom框架,是一款基于六边形架构的充血领域模型设计源码,采用Go语言开发,总计包含200个文件。文件类型涵盖了178个Go源文件、6个Markdown文档、4个TOML配置、4个YAML配置、2个SQL脚本、1个Git忽略规则、...

    领域驱动(DDD)充血模式下,domain 与 Service以及Repository的解耦---DOMAIN EVENT

    本文将详细探讨DDD中的“充血模式”(Bounded Contexts with Rich Domain Models),以及如何通过引入DOMAIN EVENT来实现domain、Service与Repository之间的解耦。 首先,我们来理解DDD的核心概念——领域模型...

    领域模型驱动设计1553265830.pdf

    - 领域模型设计:采用充血模型而非贫血模型,并且在设计中融合设计模式、流程编排、事件驱动等元素。 - 强化单测:确保代码的质量,通过单元测试来保证各个领域模型的正确性和稳定性。 - 持续重构:在业务生命周期内...

    领域模型说明及范例代码.zip

    在Java编程中,我们可以使用诸如Spring框架来实现领域模型,利用其强大的依赖注入功能,方便地将业务逻辑注入到模型对象中。同时,贫血模型也可以利用Spring的Service层来组织业务逻辑,保持模型对象的简单性。 本...

    11丨实战一(上):业务开发常用的基于贫血模型的MVC架构违背OOP吗?1

    另一方面,"充血模型"(也称为富域模型)则在领域对象中包含业务逻辑。在这种模式下,`User`对象不仅包含了数据,还包含了处理这些数据的方法,使得模型对象更加"饱满"。这种设计更符合领域驱动设计(DDD)的理念,...

    12丨实战一(下):如何利用基于充血模型的DDD开发一个虚拟钱包系统?1

    1. 充值 2. 支付 3. 提现 4. 查询余额 5. 查询交易流水

    领域驱动设计案例-盒马实践

    在充血模型中,业务逻辑是集中在中心对象中,并且使用Repository 模式来管理业务数据。 依赖注入 依赖注入是领域模型中的一种设计模式,它指的是在 runtime 时将对象之间的依赖关系注入到对象中。在 Spring 框架中...

    软件架构技术公司内部交流

    GRASP原则(Generative and Responsible Assignment of Class Principles)是软件设计中的一个重要指导原则,它包括了如控制器、多态、间接性、低耦合、高内聚、保护变化、原则导向设计等多个子原则,帮助设计师合理...

    DDD建模中的主客体思维-SACC2021年中国系统架构师大会.pdf

    文档中提到的“充血模型”是面向对象编程(OOP)中的一个概念,指的是对象不仅仅拥有数据,还包含与这些数据相关的操作方法。在DDD中,运用充血模型需要考虑如何与其他领域对象协作,以及在需要批量处理时,充血模型...

    tbl-demo-service-master.zip

    领域模型的职责是实现业务逻辑,如果领域模型只是用来处理简单的逻辑(比如贫血模型),那么领域模型的作用微乎其微,甚至可以忽略,数据转换的成本比领域模型带来的好处还多,这种情况其实就是在原有的分层架构中...

    大白话领域驱动设计DDD视频教程

    体会下充血模型开发微信钱包系统 聚合和聚合根是什么? 领域事件是什么? 看看领域事件的本质(解耦,异步,削峰) 工厂和资源库的作用? 领域服务是什么? 通过用例分析法和领域事件梳理电商购物车核心流程 第4章 DDD...

    行业分类-物理装置-一种人眼充血检测装置.zip

    标题中的“行业分类-物理装置-一种人眼充血检测装置”揭示了这个压缩包文件包含的内容属于医疗或健康科技领域,具体是一个物理装置的设计,用于检测人眼的充血情况。这种装置可能是非侵入式的,旨在帮助医疗专业人员...

    消化系统疾病动物模型.ppt

    在医学研究中,动物模型是探究疾病机制和检验治疗效果的重要工具,尤其在消化系统疾病的研究中发挥着不可替代的作用。本篇文章将详细介绍急性胃炎和慢性胃炎的动物模型构建过程,以及这些模型在医学研究中的应用和...

    DDD领域驱动设计day02.pdf

    领域驱动设计中的领域模型包括充血模型和贫血模型两种不同的建模方式。贫血模型主要存在于传统分层架构中,其特点是实体类中几乎没有业务逻辑,主要通过getter和setter方法来访问属性。这种模式下,业务逻辑分散在...

Global site tag (gtag.js) - Google Analytics