本书是Eric Evans对他自己写的《领域驱动设计-软件核心复杂性应对之道》的一本字典式的参考书,可用于快速查找《领域驱动设计》中的诸多概念及其简明解释。
其它本系列其它文章地址:
[译文]Domain Driven Design Reference(一)—— 前言
[译文]Domain Driven Design Reference(二)—— 让模型起作用
[译文]Domain Driven Design Reference(三)—— 模型驱动设计的构建模块
Ⅱ.模型驱动设计的构建模块
这些模式根据领域驱动设计,广泛地推行了面向对象设计的最佳实践。他们指导决策来提炼模型,并使模型和实现保持一致,每一个都增强了其他的有效性。仔细制定模型元素的细节为开发人员提供了一个稳定的平台,从中可以探索模型并使其与实现保持紧密联系。
分层架构
在面向对象的程序中,用户界面,数据库和其他支持代码通常会直接写入业务对象。额外的业务逻辑被嵌入在UI部件和数据库脚本的行为中。发生这种情况是因为在短期内,这样做是最简单的方法。
当与领域相关的代码通过如此大量的其他代码被扩散时,变得非常难以理解和推理。UI的表面变化实际上可以改变业务逻辑。要更改业务规则,可能需要仔细跟踪UI代码,数据库代码或其他程序元素。实现一致的、模型驱动的对象变得不切实际。自动化测试变得难以进行。由于每个活动都涉及到所有的技术和逻辑,程序必须保持非常简单,否则就无法理解。
因此:
隔离领域模型和业务逻辑的表达形式,并消除对基础架构,用户界面甚至非业务逻辑的应用程序逻辑的依赖。将一个复杂的程序分成多个层。在每个层次内开发一个内聚的设计,并且仅依赖于下面的层。遵循标准的建筑模式,为上面的分层提供松散的耦合。将所有与领域模型相关的代码集中在一个层中,并将其与用户界面,应用程序和基础设施的代码隔离。领域对象没有显示自己,存储自己,管理应用程序任务等等的职责,可以集中在表达领域模型上。这使得一个模型能够发展到足够丰富,足够清晰,能够捕获必要的业务知识并将其付诸实践。
这里的关键目标是隔离。 诸如“六边形架构”之类的相关模式可以起到允许我们的领域模型表现避免依赖和引用其他系统问题,甚至更好的效果。
实体
许多对象代表了一个连续的具有身份标识的主线,贯穿整个生命周期,尽管其属性可能会改变。一些对象不是主要由它们的属性定义的。它们代表了贯穿时间并经常跨越不同展现形式的主线的身份标识。有时这样的对象必须与另一个对象匹配,即使属性不同。错误的身份可能导致数据损坏。
因此:
当一个对象被它的身份而不是它的属性所区分时,把它作为它在模型中定义的要点。保持简单的类定义,并关注生命周期的连续性和身份标识。
定义一个区分每个对象的方法,而不管它的形式或历史。 对通过属性调用匹配对象的需求保持警惕。定义一个保证为每个对象产生唯一结果的操作,可能通过附加一个保证唯一的符号。这种标识手段可能来自外部,也可能是由系统创建的任意标识符,但必须符合模型中的身份标识区别。
模型必须定义什么是同样的事情。
(又称参考对象)
值对象
有些对象描述或计算事物的一些特征。
许多对象没有概念上的身份标识。
跟踪实体的身份标识至关重要。但将身份标识附加到其他对象可能会伤害系统性能,增加分析工作,并使所有对象看起来都一模一样。软件设计是一个复杂的持续战斗。我们必须作出区分,以便只有在必要时才进行特殊处理。
然而,如果我们把这种类型的对象看作是缺少身份的话,那么我们并没有在我们的工具箱或词汇中添加太多东西。实际上,这些对象具有自己的特点,对模型本身也有意义。 这些是描述事物的对象。
因此:
当您只关心模型元素的属性和逻辑时,将其归类为值对象。使其表达它传达的属性的含义并赋予它相关的功能。将值对象视为不可变的。使所有操作是不依赖任何可变状态的无副作用函数。不要给值对象任何身份标识,并避免保留实体所必需的设计复杂性。
领域事件
领域专家关心的事情发生了。一个实体负责跟踪其状态和规定其生命周期的规则。但是,如果你需要知道状态变化的实际原因,这通常是不明确的,并且可能很难解释系统如何实现它。审计线索可以允许跟踪,但通常不适合用于程序本身的逻辑。实体的变化历史可以允许访问先前的状态,但忽略这些变化的含义,以便对信息的任何操作都是程序性的,并且经常被抛出领域层。