关于领域驱动计划的理解

打印 上一主题 下一主题

主题 1019|帖子 1019|积分 3057

领域驱动计划是什么

2004 年埃里克·埃文斯(Eric Evans)出书了《领域驱动计划》(Domain-Driven Design
–Tackling Complexity in the Heart of Software)这本书,从此领域驱动计划(Domain Driven Design,简称 DDD)诞生。
DDD以为,软件的核心是其为用户办理领域相关的问题的本领,所有其他特性,不管有多么重要,都要服务于这个基本目的。
领域驱动计划是一种头脑方式,它提供了一整套完整的计划实践、技术和原则,加速了复杂领域的软件项目的开发。
领域驱动计划的主要内容

构造块和柔性计划

此部门也称为战术计划,主要用于应对相对小型的系统模子,主要依赖面向对象的分析技术。
构造块先容了DDD中模子中的组成要素,柔性计划先容了一些模式,用于控制模子的复杂性,以应对模子重构带来的打击。

战略计划

随着系统的不断发展,模子会变得越来越复杂,战略计划是为了应对这种大模子的技术,包括上下文、精炼和大型结构。

领域模子

主流的开发架构

目前主流的开发结构是利用Spring相关组件,接纳的典型的分层架构。


  • 界面层:包含了界面相关内容,主要是html、js和css,而且目前普遍会接纳前后端分离的方式,将界面层独立服务器摆设。
  • 应用层:主要包含了java代码,用于处置惩罚业务操作逻辑,其又分别为三层,controller、service和dao。

    • controller为控制层,用于接收请求并分发至serivce,这一层不会写复杂的逻辑
    • service为服务层,主要逻辑在这一层实现
    • dao为数据访问层,用于接入数据库

  • 数据层:为数据库存储,通常会利用关系型数据库

    在这种架构结构中,业务的模子表现在数据库表的计划中,应用层的本质是数据库的一层外皮,在这层外皮中,用java实现了业务行为逻辑,在应用层中也存在Entity的概念,是指数据库表的映射(与DDD的Entity是差别的概念)。这种架构计划主要有两个有点:一个是技术层面上更容易理解,对业务模子进行了逻辑分别,Entity负责访问数据库,Service用于处置惩罚业务逻辑;另一个是这种分层架构可以很容易实现分布式的拆分,将层独立服务器摆设。
    但在DDD中,以为这种架构把领域概念的元素分别的很零散,代码无法清楚的表现模子。
运用领域模子

领域模子的含义

在DDD中,更加夸大业务抽象和面向对象编程,而不是过程式业务逻辑实现,领域模子是DDD的关键核心。领域模子可以通俗理解为面向对象的建模,也就是对现实天下的事物或问题的抽象建模,过去也会称之为仿真,现在有个更加时髦的词汇“数字孪生”。有效的建模是一个很困难的过程,抽象的过程并没太多有效的方法,主要的就是分析业务需求中的名词和动词,分别对应对象中的属性和行为,而更多的是要依赖不断的学习和消化业务,随着对业务的深入理解,逐渐拨开征象得到本质。
UBIQUITOUS LANGUAGE

DDD中推荐极限编程的模式,推许项目所有相关职员在一起工作,在交换时需要一种同一的语言,以打破业务职员和技术职员在沟通上的停滞。
在DDD中,领域模子就是UBIQUITOUS LANGUAGE(通用语言),其中包含了类和主要操作的名称,UBIQUITOUS LANGUAGE的更改就是对模子的更改。
MODEL-DRIVEN DESIGN

模子驱动计划的含义是软件系统的各个部门都要反映出领域模子,程序的代码是领域模子的表达,任何部门的改变都是模子的改变。
结合通用语言和模子驱动计划,业务分析和系统计划的分离应调整为依赖同一的领域模子,包括编码也同样依赖领域模子,在利用DDD的项目团队中,领域模子是一样平常讨论必须利用的媒介,任何环节的修改都是领域模子的修改。

模子驱动计划构造块

分离领域

DDD中领域是重点关注的点,要想处置惩罚复杂的使命程序,需要做到关注点的分离,在计划中能够分别处置惩罚。这里接纳的经典的分层架构,分层架构的基 本原则是层中的任何元素都仅依赖于本层的其他元素或其下层的元素 ,下层不可依赖上层,分层的计划可以使各层具有内聚性。

DDD的推荐分层架构:


  • 用户界面层(或表现层):负责向用户表现信息和解释用户指令。这里指的用户可以是另一个盘算机系统,不一定是利用用户界面的人
  • 应用层:定义软件要完成的使命,并且指挥表达领域概念的对象来办理问题。这一层所负责的工尴尬刁难业务来说意义庞大,也是与其他系统的应用层进行交互的必要渠道应用层要只管简朴,不包含业务规则或者知识,而只为下一层中的领域对象协调使命,分配工作,使它们相互协作。它没有反映业务环境的状态,但是却可以具有另外一种状态,为用户或程序表现某个使命的进度
  • 领域层(或模子层):负责表达业务概念,业务状态信息以及业务规则。尽管保存业务状态的技术细节是由基础设施层实现的,但是反映业务环境的状态是由本层控制并且利用的。领域层是业务软件的核心
  • 基础设施层 :为上面各层提供通用的技术本领:为应用层通报消息,为领域层提供持久化机制,
    为用户界面层绘制屏幕组件,等等。基础设施层还能够通过架构框架来支持4个条理间的交互模式
这里的核心涵义是将领域分离,依托于其他层的支持,可以投入更多的精神去关注。
软件中所表现的模子

关联

关联是指模子对象之间的关系,包括一对一、一对多、多对多,在计划中应尽可能的减少关联,主要有以下三种方法:
(1) 规定一个遍历方向。
(2) 添加一个限定符,以便有效地减少多重关联。
(3) 消除不必要的关联。
ENTITY 实体

又称为REFERENCE OBJECT,是指 一些对象主要不是由它们的属性定义的,而是由唯一标识符定义。ENTITY可以是任何事物,只要满足两个条件即可 ,一是它在整个生命周期中具有连续性, 二是它的区别并不是由那些对用户非常重要的属性决定的。
这里应注意DDD中的ENTITY与现在主流的ENTITY不是同一个概念,主流的ENTITY更像EJB中的实体bean,是数据库表的在应用中的映射,用来进行数据库操作。
VALUE OBJECT 值对象

用于描述领域的某个方面而自己没有概念标识的对象称为VALUE OBJECT(值对象),我们只关心它们是什么,而不关心它们是谁。VALUE OBJECT经常作为参数在对象之间通报消息。它们经常是临时对象,在一次操作中被创建,然后丢弃。VALUE OBJECT可以用作ENTITY(以及其他VALUE)的属性 。VALUE OBJECT应该是不可变的,对值对象的操作通常可以通过复制和共享。
SERVICE 服务

当领域中的某个重要的过程或转换操作不是ENTITY或VALUE OBJECT的自然职责时,应该在模子中添加一个作为独立接口的操作,并将其声明为SERVICE。别的,应该使SERVICE成为无状态的。 SERVICE可以控制领域层中的接口的粒度,并且避免客户端与ENTITY和VALUE OBJECT耦合。
MODULE 模块

MODULE又称为Package。MODULE之间应该是低耦合的,而在MODULE的内部则是高内聚的 ,MODULE的名称应该是UBIQUITOUS LANGUAGE中的术语。
领域对象的生命周期

AGGREGATE

AGGREGATE就是一组相关对象的聚集。每个AGGREGATE都有一个根(root)和一个边界(boundary)。边界定义了AGGREGATE的内部都有什么。根则是AGGREGATE所包含的一个特定ENTITY。对AGGREGATE而言,外部对象只可以引用根,而边界内部的对象之间则可以相互引用。
由于根控制访问,因此不能绕过它来修改内部对象。这种计划有利于确保AGGREGATE中的对象满足所有固定规则,也可以确保在任何状态变化时AGGREGATE作为一个团体满足固定规则。
FACTORY

应该将创建复杂对象的实例和AGGREGATE的职责转移给单独的对象,这个对象自己可能没有 承担领域模子中的职责,但它仍是领域计划的一部门。提供一个封装所有复杂装配操作的接口,而且这个接口不需要客户引用要被实例化的对象的具体类。在创建AGGREGATE时要把它作为一 个团体,并确保它满足固定规则。
REPOSITORY

为每种需要全局访问的对象类型创建一个对象,这个对象相当于该类型的所有对象在内存中的一个聚集的“替身”。通过一个众所周知的全局接口来提供访问。提供添加和删除对象的方法, 用这些方法来封装在数据存储中实际插入或删除数据的操作。提供根据具体条件来挑选对象的方法,并返回属性值满足查询条件的对象或对象聚集(所返回的对象是完全实例化的),从而将实际的存储和查询技术封装起来。只为那些确实需要直接访问的AGGREGATE根提供REPOSITORY。 让客户始终聚焦于模子,而将所有对象的存储和访问操作交给REPOSITORY来完成。
实例代码

以下参考代码,基本符合以上的结构,可供参考。
实例代码
具体代码可参考关联资源:https://download.csdn.net/download/codezxhy/89530520
通过重构来加深理解

领域模子很难一次性构建出俩,是需要从初始的外貌逐渐进化为深层的模子,这种重构是必要的,每次重构都以为这一些深条理的模子的出现。对于这些必要的重构,在计划上就要支持这种改变,柔性计划就是为了支持这种改变。
将隐式概念变化为表现概念

概念的发掘需要计划职员不断思考、通过重构来实现的,其中也提供了两种模式。


  • 将过程建模为领域对象:在领域中一些复杂的逻辑过程应抽象为领域对象,可以通过SERVICE来实现
  • 表现约束 SPECIFICATION:SPECIFICATION就是一个谓词,可用来确定对象是否满足某些标准,SPECIFICATION主要用来实现校验和查询选择
  1. public class Test {
  2.    public static void main(String[] args) {
  3.        //挑选List中小于5的元素
  4.        List<Integer> list = new ArrayList<>();
  5.        list.add(1);
  6.        list.add(3);
  7.        list.add(4);
  8.        list.add(6);
  9.        //传统方式
  10.        for(int i = 0; i < list.size(); i++) {
  11.            int x = list.get(i);
  12.            if(x < 5) {
  13.                System.out.println(x);
  14.            }
  15.        }
  16.        //Stream方式 谓语
  17.        list.stream().filter(i -> i < 5).forEach(System.out::println);
  18.    }
  19. }
复制代码
柔性计划

柔性计划的本质是使模子更加清楚简朴,减轻客户端的理解负担,进而实现让重构变得简朴可行。
INTENTION-REVEALING INTERFACES 释意接口

类型名称、方法名称和参数名称组合在一起,共同形成了一个 INTENTION-REVEALING INTERFACE(释意接口),在命名类和操作时要描述它们的效果和目的,而不要表露它们是通过何种方式达到目的的,这 种方法可以使我们把注意力集中在项目上,并控制大型系统的复杂性。
SIDE-EFFECT-FREE FUNCTION 无副作用函数

我们可以宽泛地把操作分为两个大的类别:命令和查询。
多个规则的相互作用或盘算的组合所产生的结果是很难预测的。开发职员在调用一个操作 时,为了预测操作的结果,必须理解它的实现以及它所调用的其他方法的实现。如果开发职员不 得不“揭开接口的面纱”,那么接口的抽象作用就受到了限制。如果没有了可以安全地预见到结 果的抽象,开发职员就必须限制“组合爆炸”,这就限制了系统行为的丰富性。
任何对系统状态产生的影响都叫副作用,返回结果而不产生副作用的操作称为函数。
尽可能把程序的逻辑放到函数中,由于函数是只返回结果而不产生明显副作用的操作。严酷地把命令(引起明显的状态改变的方法)隔离到不返回领域信息的、非常简朴的操作中。当发现了一个非常得当承担复杂逻辑职责的概念时,就可以把这个复杂逻辑移到VALUE OBJECT中,这 样可以进一步控制副作用。
举例:
Paint是绘画类,mixIn是一个有副作用的方法,会改变Paint的属性状态
  1. public class Paint {
  2.     double volume;
  3.     int red;
  4.     int yellow;
  5.     int blue;
  6.     void minIn(Paint other) {
  7.         volume = volume + other.volume;
  8.         red = red + other.red;
  9.         yellow = yellow + other.yellow;
  10.         blue = blue + other.blue;
  11.     }
  12. }
复制代码
下面的代码把Paint的属性构建为一个值对象,并且值对象提供一个SIDE-EFFECT-FREE FUNCTION,这个函数的盘算结果很容易理解,也很容易测试,因此可以安全地利用或与其他操作进行组合。由于它的安全性很高,因此复杂的调色逻辑真正被封装起来了。利用这个类的开发职员不必理解其实现。
  1. public class Paint {
  2.     PigmentColor pigmentColor;
  3.     void minIn(Paint2 other) {
  4.         this.pigmentColor = this.pigmentColor.mixWith(other.pigmentColor);
  5.     }
  6. }
  7. public class PigmentColor {
  8.     int red;
  9.     int yellow;
  10.     int blue;
  11.     PigmentColor(int red, int yellow, int blue) {
  12.         this.red = red;
  13.         this.yellow = yellow;
  14.         this.blue = blue;
  15.     }
  16.     PigmentColor mixWith(PigmentColor other) {
  17.         return  new PigmentColor(this.red + other.red, this.yellow + other.yellow, this.blue + other.blue);
  18.     }
  19. }
复制代码
ASSERTION 断言

把复杂的盘算封装到SIDE-EFFECT-FREE FUNCTION中可以简化问题,但实体仍然会留有一些有
副作用的命令,利用这些ENTITY的人必须相识利用这些命令的后果。在这种环境下,使ASSERTION(断言)可以把副作用明确地表现出来,使它们更易于处置惩罚。
把操作的后置条件和类及AGGREGATE的固定规则表述清楚。如果在你的编程语言中不能直 接编写ASSERTION,那么就把它们编写成自动的单元测试。还可以把它们写到文档或图中(如果符合项目开发风格的话)。
CONCEPTUAL CONTOUR 概念外貌

在连续的重构过程中观察发生变化和保证稳固的规 律性,并探求能够解释这些变化模式的底层CONCEPTUAL CONTOUR
INTENTION-REVEALING INTERFACE使客户能够把对象表现为有意义的单元,而不仅仅是一些机 制。SIDE-EFFECT-FREE FUNCTION和ASSERTION使我们可以安全地利用这些单元,并对它们进行复杂的组合。CONCEPTUAL CONTOUR的出现使模子的各个部门变得更稳固,也使得这些单元更直观, 更易于利用和组合。
STANDALONE CLASS 独立的类

低耦合是对象计划的一个基本要素。尽统统可能保持低耦合。把其他所有无关概念提取到对象之外。如许类就变得完全独立了,这就使得我们可以单独地研究和理解它。每个如许的独立类都极大地减轻了因理解MODULE而带来的负担。
尽力把最复杂的盘算提取到STANDALONE CLASS(独立的类)中,实现此目的的一种方法是从存在大量依赖的类中将VALUE OBJECT建模出来。
CLOSURE OF OPERATION 闭合操作

在适当的环境下,在定义操作时让它的返回类型与其参数的类型相同。如果实现者 (implementer)的状态在盘算中会被用到,那么实现者实际上就是操作的一个参数,因此参数 和返回值应该与实现者有相同的类型。如许的操作就是在该类型的实例聚集中的闭合操作。闭合 操作提供了一个高层接口,同时又不会引入对其他概念的任何依赖。
由于返回值与实现 者的类型相匹配,因此它们可以像一系列过滤器一样被串接在一起。读写代码都变得很容易。它们并没有引入与选择子集无关的外来概念。 该模式可以实现链式操作,可以更加容易的形成声明式计划。
声明式计划

通常是指一种编程方式—把程序或程序的一部门写成一种可实行的规格。利用声明式计划时,软件实际上是由一些非常精确的属性描述来控制的。
声明式是相对命令式,举例来说:vue是声明式计划,JQuery是命令式计划
vue:
  1. <div @click="()=>aalert('ok')>hello world</div>
复制代码
JQuery:
  1. $('#app')
  2. .text('hello world')
  3. .on('click', ()=>{
  4.     alert('ok')
  5. })
复制代码
应用分析模式

分析模式是一种概念聚集,用来表现业务建模中的常见结构。它可能只与一个领域有关,也可能跨越多个领域。
将计划模式应用于模子

计划模式是用于办理一些编码问题的成熟方式,利用这些计划模式的理念,去办理领域建模中的问题。
STRATEGY 策略模式

我们需要把过程中的易变部门提取到模子的一个单独的“策略”对象中。将规则与它所控制 的行为区分开。按照STRATEGY计划模式来实现规则或可更换的过程。策略对象的多个版本表现 了完成过程的差别方式。
通常,作为计划模式的STRATEGY侧重于更换差别算法的本领,而当其作为领域模式时, 其侧重点则是表现概念的本领,这里的概念通常是指过程或策略规则。
COMPOSITE组合模式

将对象构造为树来表现部门—团体的条理结构。利用COMPOSITE,客户短可以对单独的对象和对象组合进行同样的处置惩罚。
战略计划

随着系统的增长,它会变得越来越复杂,当我们无法通过分析对象来理解系统的时候,就需要把握一些利用和理解大模子的技术了,战略计划原则必须把模子的重点放在捕获系统的概念核心,也就是系统的“远景”上。
保持模子的完整性

BOUNDED CONTEXT 限界上下文

任何大型项目都会存在多个模子。而当基于差别模子的代码被组合到一起后,软件就会出现 bug、变得不可靠和难以理解。团队成员之间的沟通变得混乱。人们往往弄不清楚一个模子不应该在哪个上下文中利用。
一个模子只在一个上下文中利用。这个上下文可以是代码的一个特定部门,也可以是某个特定团队的工作。明确地定义模子所应用的上下文。根据团队的构造、软件系统的各个部门的用法以及物理表现(代码和数据库模式等)来计划模子的边界。在这些边界中严酷保持模子的一致性,而不要受 到边界之外问题的干扰和混淆。
BOUNDED CONTEXT明确地限定了模子的应用范围,以便让团队成员对什么应该保持一致以及上下文之间怎样关联有一个明确和共同的理解。在CONTEXT中,要保证模子在逻辑上同一,而不用考虑它是不是适用于边界之外的环境。在其他CONTEXT中,会利用其他模子,这些模子具有不 同的术语、概念、规则和UBIQUITOUS LANGUAGE的技术行话。通过规定明确的边界,可以使模子保持纯粹,因而在它所适用的CONTEXT中更有效。同时,也避免了将注意力切换到其他CONTEXT时引起的混淆。跨边界的集成必然需要进行一些转换,但我们可以清楚地分析这些转换。
将差别模子的元素组合到一起可能会引发两类问题:重复的概念和假同源。
CONTINUOUS INTEGRATION 持续集成

当很多人在同一个BOUNDED CONTEXT中工作时,模子很容易发生分裂。团队越大,问题就 越大,但纵然是3、4个人的团队也有可能会碰到严重的问题。然而,如果将系统分解为更小的 CONTEXT,终极又难以保持集成度和一致性。
CONTINUOUS INTEGRATION是指把一个上下文中的所有工作充足频仍地合并到一起,并使它们 保持一致,以便当模子发生分裂时,可以灵敏发现并纠正问题。
像领域驱动计划中的其他方法一 样,CONTINUOUS INTEGRATION也有两个级别的操作:(1) 模子概念的集成;(2) 实现的集成。
建立一个把所有代码和其他实现工件频仍地合并到一起的过程,并通过自动化测试来快速查 明模子的分裂问题。严酷对峙利用UBIQUITOUS LANGUAGE,以便在差别人的头脑中演变出差别的 概念时,使所有人对模子都能达成一个共识。
CONTEXT MAP 上下文映射图


通过定义差别上下文之间的关系,并在项目中创建一个所有模子上下文的全局视图, 可以减少混乱。
CONTEXT MAP位于项目管理和软件计划的重叠部门。按照通例,人们往往按团队构造的外貌来规定边界。紧密协作的人会很自然地共享一个模子上下文。办公室的物理位臵也有影响。
识别在项目中起作用的每个模子,并定义其BOUNDED CONTEXT。这包括非面向对象子系统 的隐含模子。为每个BOUNDED CONTEXT命名,并把名称添加到UBIQUITOUS LANGUAGE中。
描述模子之间的联系点,明确所有通信需要的转换,并突出任何共享的内容。
先将当前的环境刻画出来。以后再做改变。
CONTEXT MAP无需拘泥于任何特定的文档格式。
BOUNDED CONTEXT之间的关系

SHARED KERNEL 共享内核


从领域模子中选出两个团队都同意共享的一个子集。当然,除了这个模子子集以外,还包括 与该模子部门相关的代码子集,或数据库计划的子集。这部门明确共享的内容具有特殊的地位, 一个团队在没与另一个团队商量的环境下不应擅自更改它。
CUSTOMER/SUPPLIER DEVELOPMENT TEAM 客户/供应商开发团队

在两个团队之间建立一种明确的客户/供应商关系。在筹划会议中,下游团队相当于上游团 队的客户。根据下游团队的需求来协商需要实行的使命并为这些使命做预算,以便每个人都知道 双方的约定和进度。
在迭代期间,下游团队成员应该像传统的客户一样随时回答上游团队的提问,并资助办理问题。
CONFORMIST 跟随者

当两个具有上游/下游关系的团队不归同一个管理者指挥时,CUSTOMER/SUPPLIER TEAM如许 的互助模式就不会奏效。勉强应用这种模式会给下游团队带来麻烦。
通过严酷遵从上游团队的模子,可以消除在BOUNDED CONTEXT之间进行转换的复杂性。尽管这会限制下游计划职员的风格,而且可能不会得到理想的应用程序模子,但选择CONFORMITY 模式可以极大地简化集成。别的,如许还可以与供应商团队共享UBIQUITOUS LANGUAGE。供应商 处于统治地位,因此最好使沟通变容易。他们从利他主义的角度出发,会与你分享信息。
ANTICORRUPTION LAYER 防腐层

创建一个隔离层,以便根据客户自己的领域模子来为客户提供相关功能。这个层通过另一个 系统现有接口与其进行对话,而只需对谁人系统作出很少的修改,乃至无需修改。在内部,这个层在两个模子之间进行必要的双向转换。
这种毗连两个系统的机制可能会使我们想到把数据从一个程序传输到另一个程序,或者从一 个服务器传输到另一个服务器。我们很快就会讨论技术通信机制的利用。但这些细节问题不应与 ANTICORRUPTION LAYER混淆,由于ANTICORRUPTION LAYER并不是向另一个系统发送消息的机制。 相反,它是在差别的模子和协议之间转换概念对象和操作的机制。

SEPARATE WAY 各行其道

集成总是代价高昂,而有时获益却很小,因此在各自BOUNDED CONTEXT中自行开发,相互之间不进行任何关联和交互,是最简朴有效的方式。
OPEN HOST SERVICE 开放主机服务

当一个子系统必须与大量其他系统进行集成时,为每个集成都定制一个转换层可能会减慢团队的工作速度。需要维护的东西会越来越多,而且进行修改的时候担心的变乱也会越来越多。
定义一个协议,把你的子系统作为一组SERVICE供其他系统访问。开放这个协议,以便所有 需要与你的子系统集成的人都可以利用它。当有新的集成需求时,就加强并扩展这个协议,但个 别团队的特殊需求除外。满足这种特殊需求的方法是利用一次性的转换器来扩充协议,以便使共享协议简朴且内聚。
OPEN HOST SERVICE利用一个标准化的协议来支持多方集成。它利用一个领域模子来在各系 统间进行交换,尽管这些系统的内部可能并不利用该模子。
PUBLISHED LANGUAGE 公开发布的语言

两个BOUNDED CONTEXT之间的模子转换需要一种公共的语言。 把一个精良文档化的、能够表达出所需领域信息的共享语言作为公共的通信媒介,必要时在 其他信息与该语言之间进行转换。
BOUNDED CONTEXT之间关系的权衡

差别的context关系对其他系统的控制和团队沟通能有差别的要求,在选择时需要过细权衡。
对于较大模子,这两者的要求均较高,但大模子能使团队共享语言更全面,沟通更清楚。

精炼

精炼是把一堆混杂在一起的组件分开的过程,以便通过某种情势从中提取出最重要的内容, 而这种情势将使它更有代价,也更有用,精炼可以资助我们把注意力集中于核心领域,精炼的主要目的是为核心域减负。
CORE DOMAIN 核心域

对模子进行提炼。找到CORE DOMAIN并提供一种易于区分的方法把它与那些起辅助作用的模子和代码分开。最有代价和最专业的概念要外貌分明。只管压缩CORE DOMAIN。 让最有才能的人来开发CORE DOMAIN,并据此要求进行相应的雇用。在CORE DOMAIN中积极开发能够确保实现系统蓝图的深层模子和柔性计划。
GENERIC SUBDOMAIN 通用子域

识别出那些与项目意图无关的内聚子领域。把这些子领域的通用模子提取出来,并放到单独 的MODULE中。任何专有的东西都不应放在这些模块中。
把它们分离出来以后,在继续开发的过程中,它们的优先级应低于CORE DOMAIN的优先级, 并且不要分派核心开发职员来完成这些使命(由于他们很少能够从这些使命中获得领域知识)。
别的,还可以考虑为这些GENERIC SUBDOMAIN利用现成的办理方案或“公开发布的模子” (PUBLISHED MODEL)。
当开发如许的软件包时,有以下几种选择:
选择1:现成的办理方案 购买或利用开源
选择2:公开发布的计划或模子
选择3:把实现外包出去
选择4:内部实现
DOMAIN VISION STATEMENT

写一份CORE DOMAIN的简短描述(约莫一页纸)以及它将会创造的代价,也就是“代价主张”。 那些不能将你的领域模子与其他领域模子区分开的方面就不要写了,展示出领域模子是怎样实现。这份描述要只管精简。尽早把它写出来,随着新的理解随时修改它。 DOMAIN VISION STATEMENT可以用作一个指南,它资助开发团队在精炼模子和代码的过程中 保持同一的方向。

HIGHLIGHTED CORE

1.编写一个非常简短的文档(3~7页,每页内容不必太多),用于描述CORE DOMAIN以及CORE 元素之间的主要交互过程。
2.把模子的主要存储库中的CORE DOMAIN标志出来,不用特意去分析其角色。使开发职员很容 易就知道什么在核心内,什么在核心外。
3.把精炼文档作为过程工具
COHESIVE MECHANISM 内聚机制

把概念上的COHESIVE MECHANISM(内聚机制)分离到一个单独的轻量级框架中。要特别注意公式或那些有完备文档的算法。用一个INTENTION-REVEALING INTERFACE来暴露这个框架的功能。现在,领域中的其他元素就可以只专注于怎样表达问题(做什么)了,而把办理方案的复杂 细节(怎样做)转移给了框架。
SEGREGATED CORE 分离的核心

对模子进行重构,把核心概念从支持性元素(包括定义得不清楚的那些元素)中分离出来, 并加强CORE的内聚性,同时减少它与其他代码的耦合。把所有通用元素或支持性元素提取到其他对象中,并把这些对象放到其他的包中——纵然这会把一些紧密耦合的元素分开。
此模式是一种重构核心的方法,与通用子域是相反的方式,分离核心是将最核心的领域内容在当前模子分离出去,形成更内聚的核心模子。
ABSTRACT CORE


把模子中最基本的概念识别出来,并分离到差别的类、抽象类或接口中。计划这个抽象模子, 使之能够表达出重要组件之间的大部门交互。把这个完整的抽象模子放到它自己的MODULE中, 而专用的、具体的实现类则留在由子领域定义的MODULE中。
ABSTRACT CORE(抽象核心)提供了主要概念及其交互的简化视图。
可以结合PLUGGABLE COMPONENT FRAMEWORK进行理解,高度抽象出核心模子,具体实现在其他子领域中,差别子领域只依赖抽象核心,具体子领域通过依赖注入方式调用,使子领域之间解耦合,也让核心域内容更清楚。
大型结构

在一个大的系统中,如果由于缺少一种全局性的原则而使人们无法根据元素在模式(这些模 式被应用于整个计划)中的角色来解释这些元素,那么开发职员就会陷入“只见树木,不见丛林” 的境地。
我们需要理解各个部门在团体中的角色,而不必去深究细节。 “大型结构”是一种语言,人们可以用它来从大局上讨论和理解系统。
从总体上讲,大型结构并不是必须要用的。
EVOLVING ORDER 演变的顺序

让这种概念上的大型结构随着应用程序一起演变,乃至可以变成一种完全差别的结构风格。 不要依此过分限制具体的计划和模子决议,这些决媾和模子决议必须在把握了具体知识之后才能确定。
可以理解为大模子需要随着应用程序的改变而改变。
SYSTEM METAPHOR 系统隐喻

软件计划往往非常抽象且难于把握。开发职员和用户都需要一些切实可行的方式来理解系 统,并共享系统的一个团体视图。
SYSTEM METAPHOR(系统隐喻)是一种松散的、易于理解的大型结构,它与对象范式是协调的。 由于系统隐喻只是对领域的一种类比,因此差别模子可以用近似的方式来与它关联,这使得人们能 够在多个BOUNDED CONTEXT中利用系统隐喻,从而有助于协调各个BOUNDED CONTEXT之间的工作。
举例:防火墙
RESPONSIBILITY LAYER 责任分层

如果每个对象的职责都是人为分配的,将没有同一的引导原则和一致性,也无法把领域作为 一个团体来处置惩罚。为了保持大模子的一致,有必要在职责分配上实行一定的结构化控制。
分层模式有一种变体最得当按职责来分层,我们把这种变体称为RELAXED LAYERED SYSTEM(松散分层系统) , 如果接纳这种分层模式,某一层中的 组件可以访问任何比它低的层,而不限于只能访问直接与它相邻的下一层。
注意观察模子中的概念依赖性,以及领域中差别部门的变化频率和变化的缘故原由。如果在领域 中发现了自然的条理结构,就把它们转换为宽泛的抽象职责。这些职责应该描述系统的高层目的 和计划。对模子进行重构,使得每个领域对象、AGGREGATE和MODULE的职责都清楚地位于一个 职责层当中。


KNOWLEDGE LEVEL


当我们需要让用户对模子的一部门有所控制,而模子又必须满足更大的一组规则时,可以利用KNOWLEDGE LEVEL(知识级别)来处置惩罚这种环境。 它可以使软件具有可设置的行为,其中实体中的角色和关系必须在安装时(乃至在运行时)进行修改。
如果在一个应用程序中,ENTITY的角色和它们之间的关系在差别的环境下有很大变化,那么复杂性会显著增加。在这种环境下,无论是一般的模子照旧高度定制的模子,都无法满足用户的需求。为了兼顾各种差别的情况,对象需要引用其他的类型,或者需要具备一些在不怜悯况下包括差别利用方式的属性。具有相同数据和行为的类可能会大量增加,而这些类的唯一作用只是为 了满足差别的组装规则。
创建一组差别的对象,用它们来描述和约束基本模子的结构和行为。把这些对象分为两个“级别”,一个黑白常具体的级别,另一个级别则提供了一些可供用户或超等用户定制的规则和知识。

PLUGGABLE COMPONENT FRAMEWORK 可插入式组件框架

从接口和交互中提炼出一个ABSTRACT CORE,并创建一个框架,这个框架要答应这些接口的各种差别实现被自由更换。同样,无论是什么应用程序,只要它严酷地通过ABSTRACT CORE的接 口进行操作,那么就可以答应它利用这些组件。
一个缺点是它是一种非常难以利用的 模式。它需要高精度的接口计划和一个非常深入的模子,以便把一些必要的行为捕获到 ABSTRACT CORE中。
总结

毫无疑问,软件的核心是业务,但在软件行业的发展进程中,大部门人的精神是投入到一些基础组件的研发当中, 领域驱动计划是险些是唯一对于领域复杂性进行研究的理论。
在本次通读册本后,想将DDD归纳为:面向对象计划+极限编程的理念来应对应对领域复杂性,其理论的核心内容就是面向对象计划的模子贯穿始终,以及在计划中始终贯彻将模子表达的完整、清楚、简朴。如此概况可能也不甚正确,但此理论中提到的相关模式确实可以在系统计划过程中资助办理一些问题。
结合近况来看,领域驱动计划的落地黑白常困难的,很难将书中提到所有模式逐一利用,但判断是否为DDD的标志也并不是如此,最标志性的特性是把“理解目的领域并将学到的知识融合到软件中”当作首要使命。
最后,此篇是我对《领域驱动计划 软件核心复杂性应对之道》的读书心得,与各位共勉,创建好的软件是一项需要学习和思考的活动。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

吴旭华

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表