现在的位置: 首页 > 综合 > 正文

《领域驱动设计:软件核心复杂性应对之道》 随笔(二)

2012年05月28日 ⁄ 综合 ⁄ 共 2371字 ⁄ 字号 评论关闭

《领域驱动设计:软件核心复杂性应对之道》 随笔(二)

对象间的关联可以非常容易地得到,也很容易画出来,但是实现它们却不是那么容易。关联也表明,对于模型驱动设计来说,详细的实现决策是多么重要。

 

让我们专向对象本身,但是我们仍然将继续关注模型的细节选择与实现事宜之间的联系。我们将对用来表述模型的模型元素的3种模式进行划分。这3种模式分别为:实体(Entity)、值对象(Value Object)和服务(Service)。

 

从表面上来看,把捕获了领域关键概念的对象定义出来时非常容易的;但实际上,要捕捉隐藏在表象之下的概念却是一种很大的挑战。这就要求对模型元素的意义进行明确的区分,并把它应用到设计实践当中,来创建一些特定类型的对象。

 

一个对象所代表的事物是一个具有连续性和标识的概念,还是只是一个用来描述事物的某种状态的属性? 这就是实体与值对象最基本的区别。

 

建模与实现之间的相互影响使得对象之间的关联变得特别难以处理。

 

对于模型中的每个导航(traversable)的关联,在软件中都会提供一种机制来维护与之相同的特性。

 

至少有3种方法可以使得关联易于控制。

指定一个导航的方向

通过加入限定符(qualifier)来有效地减少关联的多重性(multiplicity

清除不必要的关联

 

尽可能地约束关联是非常重要的。一个双向关联意味着,只有这两个对象同时放在一起时才能被理解。如果应用并不要求在两个对象间进行双向交互,那么指定一个导航方向可以降低对象的相互依赖性,并且使设计得到简化。充分地理解领域可以克服一些主观偏见。

 

有些对象并不主要是由它们的属性来定义。它们体现了标识在时间上的延续性,经常要经历多种不同的形态。有时,一个对象与另一个对象有着不同的属性,但它们是互相匹配的;有时一个对象与其他对象有着相同的属性,但它必须能够跟那些区分开来。弄错对象标识会导致数据破坏。

 

以标识作为其基本定义的对象称为“实体”。在建模与设计时需要做特殊的考虑。在实体的生命周期中,其存在形式和内容可以发生很大的变化,但必须保证其标识的连续性。

 

当然,在软件系统中绝大多数实体都不是平常所说的人或者实体。只要一个对象在生命周期中能够保持连续性,并且独立于它的属性,那它就是一个实体。这样的对象可以是人、城市、汽车、彩票或银行交易。

 

如果一个对象是通过标识而不是属性来确定的,那么就在模型中把标识作为这个对象定义的基本要素。保持类的定义简单明了,并着重考虑其生命周期的连续性和唯一性。定义对象的方法要能够把每个不同的对象区分开来,而无需去考虑它的形态和历史。对那些需要通过属性比较来匹配对象的情况保持警惕。确保生成标识的操作能够为每个对象产生唯一的结果,这可以通过在标识中附加一个具有唯一性保证的符号来实现。生成的标识可能来自外界,也可能是由使用这些标识的系统随机产生的;不管用什么方法,标识必须满足其在模型中所具有的唯一性。模型必须对“怎么才是同一个事物”的具体含义作出定义。

 

标识并不是现实实体所固有的,它之所以意义重大,是因为它非常有用。事实上,现实世界中的同一个事物在领域模型中有可能表示为实体,也有可能不表示为实体。

 

如果一个对象代表了领域的某种描述性特征,并且没有概念性的标识,我们就称之为值对象。值对象就是那些设计中我们只关心它们是什么,而不关心它们谁是谁的对象。

 

如果我们只关心模型中一个元素的属性,那么就把这个元素划分为值对象。用它来描述它所要表达的那些属性的意义,并且提供相应的功能。把值对象看成是不可变的。不要给它任何标识,这样可以避免实体的维护工作,降低设计的复杂性。

 

实体和值对象是传统对象模型的主要元素,但是注重实效的设计者已经开始使用另一个元素:服务。

 

领域中的一些概念不能作为模型的对象来处理。将领域需要的功能强行加给实体和值对象,不会破坏模型中对象的定义,而且还会人为地添加没有意义的对象。

 

服务作为一种接口提供操作,它独立于模型,没有像实体和值对象那样封装状态。服务在技术框架中是一种通用模式,但是它也可以应用于领域层。

 

所谓服务,它强调与其他对象的联系。不像实体和值对象,服务完全是根据能够为客户做什么来定义的。服务往往代表一种行为,而不是一个实体,是一个动词而不是一个名词。服务可以有一个抽象的、有意图的定义,这与一个对象的定义有所不同。服务应该还有一个定义好的职责,它的职责和接口被定义为领域模型的一部分。操作名应该来自通用语言,如果通用语言还没有这个操作名,则应该把它添加进去。调用的参数和返回的结果应该是领域对象。

 

使用服务时要小心,不能剥夺实体和值对象的所有行为。但是当一种操作确实是一个重要的领域概念时,服务就很自然地成为了模型驱动设计中的一部分。在模型中声明的服务,不是一个并不代表任何东西的对象,它的独立操作不会误导任何人。

 

一个优秀的服务具备3种特征:

与领域概念相关的操作不是实体和值对象中固有的部分

与接口根据领域模型中的其他元素来定义

操作是无状态的

 

这里的无状态是指任何一个客户都可以使用服务的所有实例,而不管这个实例的来源。服务的执行将使用全局可访问的信息,甚至改变这些信息。但服务不保留影响自己行为的状态,而绝大多数领域对象是要保留这些状态的。

 

当领域中的一个重要进程或转换操作不是实体和值对象本身的职责时,把操作作为一种独立的接口加入模型,并声明为服务。根据模型中使用的语言来定义接口,保证操作名是通用语言中的一部分。使这个服务变成无状态的。

 

这种模式只关心那些在领域中有重要意义的服务,当然,服务不知是应用于在领域层上。要仔细区分领域层和其他层上的服务,仔细分解它们的职责,将它们明确区分开来。

 

文献中讨论的绝大多数服务是存技术上的,属于基本结构层。领域层和应用层的服务要与基础架构层的服务合作。

抱歉!评论已关闭.