您的位置:首页 > 编程语言

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

2008-05-20 10:54 316 查看
领域驱动设计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的观点是:


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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐