AICon上海|与字节、阿里、腾讯等企业共同探索Agent 时代的落地应用 了解详情
写点什么

没有依赖注入和面向方面编程,能很好地进行领域驱动设计吗?

  • 2008-03-04
  • 本文字数:2408 字

    阅读完需:约 8 分钟

领域驱动设计(DDD)的主要思想是在设计中将业务领域中的概念与软件元素对应起来,面向对象的编程方法(OOP)是DDD 实现中的核心要素。OOP 中的对象就代表现实中某个实体。在充分利用诸如继承、封装和多态等OOP 概念的基础上, 领域对象会被设计成简单Java 类和接口。

在一个典型的业务单元中,领域对象通常需要与其他对象协同工作,无论此对象是服务(Service) 仓库(Repository) 还是工厂(Factory)。与此同时,诸如领域状态变化跟踪、审核、缓冲、事务管理(包括事务重试)之类的横切关注点也是领域对象必须密切关注的。然而,这些东西大都是可重用的并且是非领域相关的,它们往往会散布或者重复出现在包括领域层的所有代码中。这些嵌入领域代码中的非领域逻辑往往会导致领域层的繁杂与混乱。

为了很好管理代码间依赖,同时解耦领域对象与独立的横切关注点,只使用OOP 技术往往不能为领域驱动设计提供一流的设计和开发解决方案。正是由于这些原因催生了依赖注入 (DI) 和面向方面编程 (AOP) 等概念。它们作为 OOP 的补充,能很好地减少代码间紧密耦合、增加产品模块化特性和管理横切关注点。

以上就是 DomainDrivenDesign 用户组的论坛最近一个帖子讨论的主题。讨论由Ramnivas Laddad 有关DDD 的一段演讲引出,在陈述中他断言DDD 在没有AOP 和DI 辅助的情况下是无法完全实现的。Ramnivas 谈到了应用AOP 实现细粒度DI 这一概念,他认为此概念能使领域对象的行为更合理。他还提到领域对象如果想要有丰富的功能行为,就必须有权使用其他细粒度的对象,这往往是通过将服务、工厂或者仓库注入到领域对象中实现的(使用Aspects 在构造函数或者 setter 函数中进行注入 )。

管理域对象之间的依赖关系(例如实体与其仓库间依赖)是任何一个 DDD 开发者都会涉及的典型问题。通常的设计解决方法是让 Service 或者 Façade 直接调用 Repository,Repository 获得实体对象后将其返回给调用者。这种设计方式往往会导致胖服务层和贫血模型( Anemic Domain Model )的出现,结果就是 façade 类会开始堆积越来越多的业务逻辑,领域对象也逐渐变成只有一些 setter 和 getter 函数的纯粹的数据载体。

InfoQ 与 Ramnivas Laddad 和《领域驱动设计》一书的作者 Eric Evans 就 DDD 实现中 DI 和 AOP 的角色问题进行了讨论。当谈到 DDD 在没有 AOP 和 DI 辅助的情况下是无法完全实现的这一断言时,Ramnivas 认为这个结论的重要前提是领域对象如果想要表现得更灵活,与 Repositories 和 Services 这样的对象打交道是不可避免的。

问题的关键是领域对象怎样得到此类对象?DI 似乎是个正确的选择。AOP 此时也正好派上用场,它将类 Spring 的 DI(将 DI 限制在 application context 中声明的对象范围内)扩展到任意的对象,而不管它是在哪里创建的。当然,AOP 也会在任何领域层面的横切关注点上起作用(此处的基本假设是领域概念应尽可能地映射到某一软件制品上)。

Eric 在谈到 OOP、DI 和 AOP 为何非常适合实现 DDD 时说:

虽然 DDD 能用任何范式实现,只要这些范式支持抽象并且能表达领域概念就行。但在实际应用中人们的选择几乎总是 OOP。因此说 OOP 是 DDD 实践的基础。 DI 目前已经成为了一项广为人知的技术,如果应用得当,它能帮助 DDD 实践者改善设计。在我看来,最重要的还是 DI 实现了领域的隔离。

人们正逐渐认识 AOP 的潜力。这种潜力就是它可以改变领域层的杂乱状态。这对领域概念的清晰表达甚至领域隔离非常有帮助。但是,它还不是“基础”(译者注:指 OOP)的一个经受过实践检验的组成部分,在这一点上它还是跟 OOP 和 DI 有区别的。

以上这些就形成了目前支持 DDD 的最佳实践架构的基础。

他还强调说弄清设计思想(DDD)与能帮助我们实现这种思想的技术工具(OOP、DI 甚或 AOP)间的界限也是非常重要的。

近来定义和管理 Aspects 和 DI 的趋势是应用注释(Annotations)。Spring 采用 @Configurable 将 Repository 和 Services 注入到领域对象。InfoQ 就注释(Annotations)在 DDD 项目中的角色问题咨询了 Eric:

通常,任何依附于某个对象并且代表领域中某个概念的东西,包括注释(Annotation),应该在概念上与此对象有某种联系。@Configurable 属于技术范畴,并非属于领域范畴,因此我不赞成给领域对象加上这样的注释。在另一方面,对 Repository 来说,我一般会有一个接口和一个实现类。我将接口看作其中的领域部分,尽量保持其纯概念化。但是实现类往往会引用某种技术(例如 DAO 是这些技术中的典型代表)。这样在 Repository 的实现类中应用 @Configurable 注释就合情合理了。

在 @Configurable 注释之外,Spring 框架继续扩展了“领域依赖注入”的思想。Ramnivas 最近写了一篇关于 Spring2.5.2 版本( project snapshot build 379 )最新进展的博客文章。Spring2.5.2 有三个新的方面(AnnotationBeanConfigurerAspect, AbstractInterfaceDrivenDependencyInjectionAspect 和 AbstractDepndencyInjectionAspect),它们为领领域对象的依赖注入提供了简单并且灵活的选择。Ramnivas 说引入前述第二个方面(AbstractInterfaceDrivenDependencyInjectionAspect)的目的是让特定领域的注释和接口能起到应有的作用。他最后补充道 @Configurable 虽说是一个简单的选项,但它往往不是最优雅的。

目前也有了一些关于服务编排(对多步骤的业务单元来说)和业务对象生命周期的讨论。在关于 BPEL 是怎样影响领域对象生命周期和不同领域对象之间交互这一问题上,Eric 的观点是:

服务编排和对象生命周期是很微妙的一对概念。服务编排是一种将解耦的业务片段重新结合在一起同时又能描述出工作流程的重要方法。在另一方面,在领域实体有一定的生命周期并且这些周期处于建模的中心地位的情况下,让编制层来管理对象生命周期,领域对象里面就没剩多少东西了。不过此问题并没有现成的标准答案。对设计者设计好坏的评估要个别分析,不能一概而谈。

查看英文原文: Can DDD be Adequately Implemented Without DI and AOP?

2008-03-04 23:143255
用户头像

发布了 23 篇内容, 共 49906 次阅读, 收获喜欢 3 次。

关注

评论

发布
暂无评论
发现更多内容

Hive中,同时存在map、array、struct这三种格式,应如何在建表语句中指定分隔符?

Geek_de9857

hive struct map array 分隔符

原创 | 使用JPA实现DDD持久化-启动JPA程序+通过JPA原生API访问数据

编程道与术

Java hibernate 编程 mybatis jpa

基于区块链的政务平台设计探索

华为云开发者联盟

区块链 架构 安全

架构师训练营第四周命题作业

Geek_xq

一文详解激活函数

书豪

eCharts -- 如何修改柱状图中相关数据的顺序?如何在鼠标悬浮时增加百分比信息?如何为柱状图设置分组?

Geek_de9857

柱状图 eCharts 修改数据顺序 百分比提示信息 设置分组

一周信创舆情观察(12.7~12.13)

统小信uos

佛萨奇Forsage系统开发,智能合约dapp技术

薇電13242772558

智能合约 dapp

终于有人把性能优化讲清楚了!阿里架构师推荐的Java性能权威指南可太强了

Java架构之路

Java 程序员 架构 面试 编程语言

原创 | 使用JPA实现DDD持久化-通过Spring Data JPA访问数据

编程道与术

Java hibernate 编程 mybatis jpa

flink 使用curl,通过RESTful api,上传和删除jar包

Geek_de9857

flink RESTful curl 上传jar 删除jar

滴滴DoKit阶段性成果汇报之一机多控

工具 滴滴开源 DoKit

阿里云容器服务入选云原生边缘「领导力企业TOP3」,推动「原生云边」基础设施标准建立

阿里巴巴云原生

阿里云 容器 开发者 云原生 边缘计算

原创 | 使用JPA实现DDD持久化-O/R映射元数据-关联属性映射

编程道与术

Java hibernate 编程 mybatis jpa

去 DeepMind 面试是怎样一种体验?

故胤道长

人工智能 面试 谷歌Google 硅谷 移动开发

【涂鸦物联网足迹】用煲仔饭来说明IaaS/PaaS/SaaS的区别

IoT云工坊

云计算 IaaS PaaS SaaS 云平台

原创 | 使用JPA实现DDD持久化-O/R映射元数据-值属性映射

编程道与术

Java hibernate 编程 mybatis jpa

第九周学习总结

Griffenliu

盘点 2020 | 感悟总结

idonkeyliu

盘点2020

LeetCode题解:127. 单词接龙,双向BFS,JavaScript,详细注释

Lee Chen

算法 大前端 LeetCode

Mysql中,1=1和 1=1=1 和 -1=-1 和 -1=-1=-1 和 5=5 和 5=5=5 有什么区别

Geek_de9857

MySQL sql 返回值 1=1=1 -1=1=1

JavaScript中,if判断未生效的一些特殊情况

Geek_de9857

js 1 if 0 不生效

阿里Java研发第2面,都会问什么?斩获阿里P6+的“他”告诉你答案

Java架构之路

Java 程序员 架构 面试 编程语言

15年华为云视频架构师采访实录:揭秘未来音视频行业的科技趋势!

华为云开发者联盟

直播 视频 华为云

自从看了百度强推的“Spring源码笔记”我从渣渣成功逆袭成为钢铁侠!

比伯

Java 架构 程序人生 计算机 spring源码

架构师训练营 1 期 -- 第十三周作业

曾彪彪

极客大学架构师训练营

第九周作业

Griffenliu

读《全球创新投资:经济大变局中的财富新机遇》

邓瑞恒Ryan

创业 读书笔记 企业 企业管理 产业竞争

原创 | 使用JPA实现DDD持久化-O/R映射元数据-值和关联的比较+继承映射

编程道与术

Java hibernate 编程 mybatis jpa

阿里Java岗面试必备JVM指南:内存分配+垃圾回收+调优+类加载器等

Java架构之路

Java 程序员 架构 面试 编程语言

Java程序员还没有掌握SpringBoot?这一份文档你真应该好好学学!

Java架构之路

Java 程序员 架构 面试 编程语言

没有依赖注入和面向方面编程,能很好地进行领域驱动设计吗?_架构_Srini Penchikala_InfoQ精选文章