【DDD】领域驱动设计实践 —— 框架实现

本文主要了在社区服务系统(ECO)中基于SpringMVC+mybatis框架对DDD的落地实现。本文为系列文章中的其中一篇,其他内容可参考:通过业务系统的重构实践DDD。

框架实现图

该框架实现基本和DDD的指导思想契合,主要分为四层,且将关注点放在了domain层。下面将逐层介绍各个组件的职责。

框架详述

User Interface层

门面层,对外以各种协议提供服务,该层需要明确定义支持的服务协议、契约等。包含:

dto

包括request和response两部分,通过它定义入参和出参的契约,在dto层可以使用基础设施曾的validation组件完成入参格式校验;

controller

支持不同访问协议的控制器实现,比如:http/restful风格、tcp/二进制流协议、mq消息/json对象等等。

controller使用基础设施层公共组件完成许多通用的工作:

  • 调用RequestMapping(SpringMVC公共组件)完成servlet路由;
  • 调用checklogin完成登录态/权限校验;
  • 调用logging组件完成日志记录;
  • 调用message-resource组件完成错误信息转义,支持I18N;

application层

service

应用服务层,组合domain层的领域对象和基础设施层的公共组件,根据业务需要包装出多变的服务,以适应多变的业务服务需求。

应用服务层主要访问domain领域对象,完成服务逻辑的包装。

应用服务层也会访问基础设施层的公共组件,如rabbitmq,完成领域消息的生产等。

assembler

组装器,负责将多个domain领域对象组装为需要的dto对象,比如查询帖子列表,需要从Post(帖子)领域对象中获取帖子的详情,还需要从User(用户)领域对象中获取用户的基本信息。

组装器中不应当有业务逻辑在里面,主要负责格式转换、字段映射等职责。

domain层

业务领域层,是我们最应当关心的一层,也是最多变的一层,需要保证这一层是高内聚的。确保所有的业务逻辑都留在这一层,而不会遗漏到其他层。按照ddd(domain driven design)理论,主要有如下概念构成:

domain entity

领域实体。有唯一标识,可变的业务实体对象,它有着自己的生命周期。比如社区这一业务领域中,‘帖子’就是一个业务实体,它需要有一个唯一性业务标识表征,同时他的状态和内容可以不断发生变化。

domain value object

领域值对象。可以没有唯一性业务标识,且一旦定义,他是不可变的,它通常是短暂的。这和java中的值对象(基本类型和String类型)类似。比如社区业务领域中,‘帖子的置顶信息’可以理解为是一个值对象,不需要为这一值对象定义独立的业务唯一性标识,直接使用‘帖子id‘便可表征,同时,它只有’置顶状态‘和’置顶位置‘,一旦其中一个属性需要发生变化,则重建值对象并赋值给’帖子‘实体的引用,不会对领域带来任何负面影响。

domain factory

领域对象工厂。用于复杂领域对象的创建/重建。重建是指通过respostory加载持久化对象后,重建领域对象。

domain service

领域服务。区别于应用服务,他属于业务领域层。

可以认为,如果某种行为无法归类给任何实体/值对象,则就为这些行为建立相应的领域服务即可。比如:转账服务(transferService),需要操作借方/贷方两个账户实体。

传统意义上的util static方法中,涉及到业务逻辑的部分,都可以考虑归入domain service。

domain event

领域事件。领域中产生的一些消息事件,通过事件通知/订阅的方式,可以在性能和解耦层面得到好处。

repository

仓库。我们将仓库的接口定义归类在domain层,因为他和domain entity联系紧密。仓库用户和基础实施的持久化层交互,完成领域对应的增删改查操作。

仓库的实际实现根据不同的存储介质而不同,可以是redis、oracle、mongodb等。

鉴于现在社区服务的存储介质有三套:oracle、redis、mongodb,且各个存储介质的字段属性名不一致,因此需要使用translator来做翻译,将持久化层的对象翻译为统一的领域对象。

translator

翻译器。将持久化层的对象翻译为统一的领域对象。

翻译器中不应当有业务逻辑在里面,主要负责格式转换、字段映射等职责。

infrastructure层

基础设施层提供公共功能组件,供controller、service、domain层调用。

repository impl

对domain层repository接口的实现,对应每种存储介质有其特定实现,如oracle的mapper,mongodb的dao等等。repository impl会调用mybatis、mongo client、redis client完成实际的存储层操作。

checkLogin

权限校验器,判定客户端是否有访问该资源的权限。提供给User Interface层的Controller调用。

exception

异常分类及定义,同时提供公共的异常处理逻辑,具体由ExceptionHandler实现。

transport

transport完成和第三方服务的交互,可以有多种协议形式的实现,如http+json、tcp+自定义协议等,配套使用的还有Resolver解析器,用于对第三方服务的请求和响应进行适配,提供一个防腐层(AnticorruptionLayer,DDD原书P255)的作用。

transcation

提供事务管理,交给Spring管理。

logging

日志模块,记录trace日志,使用log4j完成。

message resource

消息资源管理,交给Spring统一管理。

模块结构

本节介绍ECO系统的模块结构,由于是使用java语言实现,也就是java工程中的包结构,可以直观地看出框架的落地实现效果。

各个package的详细解释参考上节框架详述,着重注意如下几点:

  • factory是专职为model服务的,因此放入对应的entity的modle package中;
  • domain.repository包里面只有仓库的接口定义,实际的实现交给了infrastrcture中的repository module,该做法被称作"依赖倒置",好处在于确保domoain层语义完整,同时对确保业务领域的一致性也有帮助,再者可以在domain实现内存形式的repository哑实现,从而让domain可以真正脱离掉infrastructure;
  • translator module正常情况下不需要,但在重构老系统时,往往需要隔离掉存储模型对业务模型的影响,使用translator来讲存储模型翻译为业务模型;
  • infrastructure.repository作为仓库层,会将实体的增删改查操作委托给具体的存储层服务,如oracle对应的mapper实现,mongodb对应dao实现,还有redis的实现;
  • ECO中domain event的生产者和消费者实现均交给infrastructure.rabbitmq package实现。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结