1. 架构概述
领域驱动设计(Domain Driven Design)有一个官方的sample工程,名为DDDSample,官网:http://dddsample.sourceforge.net/,该工程给出了一种实践领域驱动设计的参考架构,本文将对此该架构进行简单介绍,并就一些重要问题进行讨论。
该架构分成了Interfaces、Applications和Domain三层以及包含各类基础设施的Infrastructure。下图简略描述了它们之间的关系:
图1 领域驱动设计风格的架构草图(来自于DDDSample官网)
下图是详细架构:
图2 领域驱动设计参考架构
作为参照,下图展示了传统TransactionScript风格的架构,可以看出,两者的差异并不是太大(对于Fa?ade来说,它是一种可 选设施,如果系统架构中省略Fa?ade,则DTO与领域对象的互换工作可在service中进行),这也从则面说明推行领域驱动设计的关键并不在架构 上,而在于整个团队在分析、设计和开发上没有自始至终地以领域模型为核心开展工作,以面向对象的思想进行设计和编程。
Transaction Script风格的架构具有明显的“数据”与“操作”分离的特征,其和领域驱动设计风格的架构在两个类组件上有质的区别,一个是领域对象,一个是 Service。领域驱动设计的架构核心目标是要创建一个富领域模型,其典型特征是它的领域对象具有丰富的业务方法用以处理业务逻辑,而 Transaction Script风格的领域对象则仅仅是数据的载体,没有业务方法,这种领域也被称作“贫血的领域对象”(Anemic Domain Objects)。在Service方面,领域驱动设计的架构里Service是非常“薄“的一层,其并不负责处理业务逻辑,而在 TransactionScript风格的架构里,Service是处理业务逻辑的主要场所,因而往往非常厚重。
图3. 数据与操作分离的Transaction Script风格的架构
2. 架构详解
2. 1 Interfaces-接口层
领域驱动设计对Interfaces的定位是:
Thislayer holds everything that interacts with other systems, such as web services,RMI interfaces or web applications, and batch processing frontends. It handlesinterpretation, validation and translation of incoming data. It also handlesserialization of outgoing data, such as HTML or XML across HTTP to web browsersor web service clients, or DTO classes and distributed facade interfaces forremote Java clients.
该层包含与其他系统进行交互的接口与通信设施,在多数应用里,该层可能提供包括Web Services、RMI或Rest等在内的一种或多种通信接口。该层主要由Facade、DTO和Assembler三类组件构成,三类组件均是典型的 J2EE模式,以下是对三类组件的具体介绍:
2.1.1 DTO
DTO- DataTransfer Object(数据传输对象),也常被称作VO-Value Object(值对象)。基于面向对象技术设计的领域对象(即通常所说的“实体”)都是细粒度的,将细粒度的领域对象直接传递到远程调用端需要进行多次网 络通信,DTO在设计之初的主要考量是以粗粒度的数据结构减少网络通信并简化调用接口。以下罗列了DTO的多项作用:
-
Reduces network traffic
-
Simplifies remote object and remote interface
-
Transfers more data in fewer remote calls
-
Reduces code duplication
-
Introduces stale transfer objects
-
Increases complexity due to synchronization and version control
图4. DTO应用时序图(基于《Core J2EE Patterns》插图进行了修改)
值得一提的是,DTO对实现一个独立封闭的领域模型具有积极的作用,特别是当系统使用了某些具有自动脏数据检查(automatic dirty checking)机制的ORM框架时,DTO的优势就更加明显,否则就会存在领域对象在模型层以外被意外修改并自动持久化到数据库中的风险或者是像 Hibernate那样的框架因未开启OpenSessionInView (注:开启OpenSessionInView有副作用,一般认为OpenSessionInView不是一种好的实践)而导致Lazy Loading出现问题。
关于DTO具体的设计用意和应用场景可参考如下资源:
-
《Core J2EE? Patterns: Best Practices and Design Strategies, SecondEdition》
-
《Patterns of Enterprise ApplicationArchitecture》
2.1.2 Assembler
在引入DTO后,DTO与领域对象之间的相互转换工作多由Assembler承担,因此Assembler几乎总是同DTO一起出现。也有一些 系统使用反射机制自动实现DTO与领域对象之间的相互转换,Appache的Commons BeanUtils就提供了类似的功能。应该说这两种实现各有利弊,使用Assembler进行对象数据交换更为安全与可控,并且接受编译期检查,但是代 码量明显偏多。使用反射机制自动进行象数据交换虽然代码量很少,但却是非常脆弱的,一旦对象属性名发生了变化,数据交互就会失败,并且很难追踪发现。总体 来说,Assembler更为直白和稳妥。
图5. Assebler应用类图(基于《Core J2EE Patterns》插图进行了修改)
关于Assembler具体的设计用意和应用场景可参考如下资源:
-
《Core J2EE? Patterns: Best Practices and Design Strategies, SecondEdition》
-
《Patterns of Enterprise ApplicationArchitecture》
2.1.3 Facade
作为一种设计模式同时也是Interfaces层内的一类组件,Facade的用意在于为远程客户端提供粗粒度的调用接口。Facade本身不 处理任何的业务逻辑,它的主要工作就是将一个用户请求委派给一个或多个Service进行处理,同时借助Assembler将Service传入或传出的 领域对象转化为DTO进行传输。以下罗列了Facade的多项作用:
-
Introduces a layer that provides services to remote clients
-
Exposes a uniform coarse-grained interface
-
Reduces coupling between the tiers
-
Promotes layering, increases flexibility and maintainability
-
Reduces complexity
-
Improves performance, reduces fine-grained remote methods
-
Centralizes security management
-
Centralizes transaction control
-
Exposes fewer remote interfaces to clients
实践Facade的过程中最难把握的问题就是Facade的粒度问题。传统的Service均以实体为单位进行组织,而Facade应该具有更 粗粒度的组织依据,较为合适的粒度依据有:一个高度内聚的模块一个Facade,或者是一个“聚合”(特指领域驱动设计中的聚合)一个Facade.
图6. Facade应用类图(基于《Core J2EE Patterns》插图进行了修改)
图7. Facade应用时序图(基于《Core J2EE Patterns》插图进行了修改)
关于Assembler具体的设计用意和应用场景可参考如下资源:
-
《Core J2EE? Patterns: Best Practices and Design Strategies, SecondEdition》
-
《Patterns of Enterprise ApplicationArchitecture》
-
《Design Patterns: Elementsof Reusable Object-Oriented Software》
2.2 Application-应用层
领域驱动设计对Application的定位是:
Theapplication layer is responsible for driving the workflow of the application,matching the use cases at hand. These operations are interface-independent andcan be both synchronous or message-driven. This layer is well suited forspanning transactions, high-level logging and security. The application layeris thin in terms of domain logic - it merely coordinates the domain layerobjects to perform the actual work.
Application层中主要组件就是Service,在领域驱动设计的架构里,Service的组织粒度和接口设计依据与传统 Transaction Script风格的Service是一致的,但是两者的实现却有着质的区别。TransactionScript风格的Service是实现业务逻辑的主 要场所,因此往往非常厚重。而在领域驱动设计的架构里,Application是非常“薄”的一层,所有的Service只负责协调并委派业务逻辑给领域 对象进行处理,其本身并真正实现业务逻辑,绝大部分的业务逻辑都由领域对象承载和实现了,这是区别系统是Transaction Script架构还是Domain Model架构的重要标志。
不管是Transaction Script风格还Domain Model风格,Service都会与多种组件进行交互,这些组件包括:其他的Service、领域对象和Repository 或 DAO。
图8. Service应用时序图(基于《Core J2EE Patterns》插图进行了修改)
Service的接口是面向用例设计的,是控制事务、安全的适宜场所。如果Facade的某一方法需要调用两个以上的Service方法,需要注意事务问题。
2.3 Domain-领域层
领域驱动设计对Domain的定位是:
Thedomain layer is the heart of the software, and this is where the interestingstuff happens. There is one package per aggregate, and to each aggregatebelongs entities, value objects, domain events, a repository interface andsometimes factories.
Thecore of the business logic belongs in here. The structure and naming ofaggregates, classes and methods in the domain layer should follow theubiquitous language, and you should be able to explain to a domain expert howthis part of the software works by drawing a few simple diagrams and using theactual class and method names of the source code.
Domain层是整个系统的核心层,该层维护一个使用面向对象技术实现的领域模型,几乎全部的业务逻辑会在该层实现。Domain层包含 Entity(实体)、ValueObject(值对象)、Domain Event(领域事件)和Repository(仓储)等多种重要的领域组件。
2.4 Infrastructure-基础设施层
领域驱动设计对Infrastructure的定位是:
Inaddition to the three vertical layers, there is also the infrastructure. As thethe picture shows, it supports all of the three layers in different ways,facilitating communication between the layers. In simple terms, theinfrastructure consists of everything that exists independently of ourapplication: external libraries, database engine, application server, messagingbackend and so on.
Also,we consider code and configuration files that glues the other layers to theinfrastructure as part of the infrastructure layer. Looking for example at thepersistence aspect, the database schema definition, Hibernate configuration andmapping files and implementations of the repository interfaces are part of theinfrastructure layer.
Whileit can be tricky to give a solid definition of what kind of code belongs to theinfrastructure layer for any given situation, it should be possible tocompletely stub out the infrastructure in pure Java unit/scenario tests andstill be able to use the domain layer and possibly the application layer towork out the core business problems.
作为基础设施层,Infrastructure为Interfaces、Application和Domain三层提供支撑。所有与具体平台、 框架相关的实现会在Infrastructure中提供,避免三层特别是Domain层掺杂进这些实现,从而“污染”领域模型。 Infrastructure中最常见的一类设施是对象持久化的具体实现。
3. 关于架构的一些讨论
3.1 架构并不能保证领域驱动设计的贯彻与执行
虽然一个合适的架构对于实施领域驱动设计是大有必要的,但只依靠架构是不能保证领域驱动设计的贯彻与执行的。实际上,在这个参考架构上使用 Transaction Script的方式进行开法几乎没有任何问题,只要开发人员将领域对象变成“贫血”的“数据载体”对待,在service里实现业务逻辑,那么该参考架构 将成为纯粹的TransactionScript方式。当然反过来看,这也体现了这一架构的灵活性。确保领域驱动设计的贯彻与执行需要整个团队在分析、设 计和开发上没有自始至终地以领域模型为核心开展工作,以面向对象的思想进行设计和编程,才能保证实现领域驱动设计。
3.2 Facade是否是必须的?
尽管在架构中对Facade的定义非常清晰,但在实践中我发现Facade并不是一个容易拿捏的东西。主要问题在于其与Service之间的有 太多的重叠与相似之处。我们注意到Service是接口是面向一个use case的,因此事务也是追加在Service这一层上,于是对于Facade而言,99%的情况是,它只是把某个Service的某个方法再包裹一下而 已,如果把领域对象和DTO的互转换工作移至Service中进行,那么Facade将彻底变成空壳,而关键的是:如果Service的接口设计是面向和 user case的,那么,毫无疑问,Service接口的传入传出参数也都应该是DTO,而这一点也在《Core J2EE Patterns: Best Practices and Design Strategies, SecondEdition》和《Patterns of Enterprise ApplicationArchitecture》两书的示例代码中完全印证了。那么,从更为务实角度出发,Facade并非是一种必须的组件。
转:https://my.oschina.net/huangcongcong/blog/538568?p=1
相关推荐
关于DDD可参考InfoQ的Mini Book Domain Driven Design Quickly , 还有 Banq 的文章 实战DDD(Domain-Driven Design领域驱动设计), 和 领域模型驱动设计(DDD)之模型提炼 。 本书分为四部分,第一部分讲述了领域模型...
《领域驱动设计精粹》(Domain-Driven Design Distilled)是Vaughn Vernon所著的一本关于领域驱动设计(Domain-Driven Design,简称DDD)的入门指南。DDD是一种软件开发的方法论,它强调在软件开发过程中,开发者...
根据提供的文件信息,我们可以提取出关于领域驱动设计(Domain Driven Design,简称DDD)的知识点。文件信息中包含了标题“Domain driven design-quickly”,描述“a quick guide on domain driven design”,以及...
读书笔记:采用领域驱动设计Domain Driven Design、DDD实现的CMS系统
读书笔记:基于DDDLib实现领域驱动设计Domain Driven Design 简称DDD实战项目
领域驱动设计(Domain-Driven Design,简称DDD)是一种处理复杂软件核心问题的方法,由Eric Evans在其2002年的著作中首次系统阐述。DDD是一种综合性的设计理念,它强调将软件开发的焦点放在业务领域,并围绕业务领域...
领域驱动设计(Domain-Driven Design,简称DDD)是一种软件开发的方法论,它由Eric Evans在其2004年的同名书籍《领域驱动设计:软件核心复杂性应对之道》中提出。DDD的核心思想是,软件系统的复杂性不仅仅是由技术...
领域驱动设计(Domain-Driven Design,简称DDD)是一种软件开发方法论,由Eric Evans在其2003年的著作《领域驱动设计:软件核心复杂性的应对之道》中提出。该方法论强调通过深入理解和分析业务领域,来驱动软件的...
领域驱动设计(Domain-Driven Design,简称DDD)是由Eric Evans在其2003年的同名书籍中首次提出的软件开发方法论。该方法论的核心思想是将软件开发的焦点集中在业务领域模型上,强调软件系统与现实世界业务领域的...
《领域驱动设计》是Eric Evans所著的一本关于软件开发的书籍,主要讨论如何解决软件开发过程中遇到的复杂问题。在本书中,作者提出了一系列关于领域模型、模型驱动设计以及如何将模型与实际实现相绑定的方法和技巧。...
Domain-DrivenDesign领域驱动设计 With this book in hand, object-oriented developers, system analysts, and designers will have the guidance they need to organize and focus their work, create rich and ...
.NET框架与C#语言结合应用领域驱动设计(Domain-driven Design, DDD)是现代软件开发中的一个重要实践。DDD旨在通过将复杂的业务逻辑集中在核心领域模型上,提高软件系统的可读性、可维护性和可扩展性。本章节我们将...
DDD(Domain-Driven Design 领域驱动设计)是由Eric Evans最先提出,目的是对软件所涉及到的领域进行建模,以应对系统规模过大时引起的软件复杂性的问题。整个过程大概是这样的,开发团队和领域专家一起通过 通用...
《应用领域驱动设计与模式》(Applying Domain-Driven Design and Patterns)是一本针对.NET平台开发人员的专业书籍,作者是Jimmy Nilsson。该书出版于2006年5月8日,由Addison Wesley Professional出版社出版。全书...
- **里程碑之一**:2004年,Eric Evans出版了《领域驱动设计:软件核心复杂性应对之道》(Domain-Driven Design: Tackling Complexity in the Heart of Software),标志着领域驱动设计(DDD)正式诞生。这本书不仅...
《Implementing Domain-Driven Design》是一本深入探讨领域驱动设计(DDD)的著作,由Eric Evans撰写,是软件开发人员尤其是架构师理解并实践DDD的重要参考书籍。领域驱动设计是一种软件开发方法,它强调通过理解和...