在DDD中应用模式

news2024/11/15 7:56:13

深层模型和柔性设计并非唾手可得。要想取得进展,必须学习大量领域知识并进行充分的讨论,还需要经历大量的尝试和失败。但有时我们也能从中获得一些优势。一位经验丰富的开发人员在研究领域问题时,如果发现了他所熟悉的某种职责或某个关系网,他会想起以前这个问题是如何解决的。以前尝试过哪些模型?哪些是有效的?在实现中有哪些难题?它们是如何解决的?先前经历过的尝试和失败会突然间与新的情况联系起来。这些模式当中有一些已经记载到文献中供大家分享,这样我们就可以借鉴这些积累的经验。
利用分析模式和设计模式,可以避免一些代价高昂的尝试和失败过程,而直接从一个已经具有良好表达力和易实现的模型开始工作,并解决了一些可能难于学习的微妙的问题。我们可以从这样一个起点来重构和试验。然而,它们并不是现成的解决方案。

应用分析模式

在《分析模式》一书中,Martin Fowler这样定义分析模式[Fowler 1997, p. 8]:分析模式是一种表示业务建模中的常见构造的概念集合,用来表示业务建模中的常见结构。它可能只与一个领域有关,也可能跨越多个领域。
Fowler所提出的分析模式来自于实践经验,因此只要用在合适的情形下,它们会非常实用。对于那些面对着具有挑战性领域的人们,这些模式为他们的迭代开发过程提供了一个非常有价值的起点。"分析模式"这个名字本身就强调了其概念本质。分析模式并不是技术解决方案,他们只是些参考,用来指导人们设计特定领域中的模型。
但从这个名字中我们看不出分析模式也讨论了大量实现问题,包括一些代码。Fowler知道,在不考虑实际设计的情况下进行单纯的分析是有缺陷的。下面举一个很有趣的例子,在这个例子中,Fowler用更长远的眼光审视了模型选择的意义——考虑在部署之后,模型选择对系统长期维护的影响[Fowler 1997, p. 151]。
在一个成熟的项目上,模型选择往往是根据实用经验做出的。人们已经尝试了各种组件的多种实现方法。其中的一些实现已经被采用,有些甚至已经到了维护阶段。这些经验可以帮助人们避免很多问题。**分析模式的最大作用是借鉴其他项目的经验,把那些项目中有关设计方向和实现结果的广泛讨论与当前模型的理解结合起来。**脱离具体的上下文来讨论模型思想不但难以落地,而且还会造成分析与设计严重脱节的风险,而这一点正是MODEL-DRIVEN DESIGN坚决反对的。用实际的例子比用单纯的抽象描述能够更好地解释分析模式的原则和应用。
本章的目的不是对分析模式进行归纳分类,本章的重点是说明如何将它们集成到领域驱动的设计过程中。

分析模式的价值

当你可以幸运地使用一种分析模式时,它一般并不会直接满足你的需求。但它为你的研究提供了有价值的线索,而且提供了明确抽象的词汇。它还可以指导我们的实现,从而省去很多麻烦。
我们应该把所有分析模式的知识融入到知识消化和重构的过程中,从而形成更深刻的理解,并促进开发。当我们应用一种分析模式时,所得到的结果通常与该模式的文献中记载的形式非常相像,只是因具体情况不同而略有差异。但有时完全看不出这个结果与分析模式本身有关,然而这个结果仍然是受该模式思想的启发而得到的。
但有一个误区是应该避免的。当使用众所周知的分析模式中的术语时,一定要注意,不管其表面形式的变化有多大,都不要改变它所表示的基本概念。这样做有两个原因,一是模式中蕴含的基本概念将帮助我们避免问题,二是(也是更重要的原因)使用被广泛理解或至少是被明确解释的术语可以增强UBIQUITOUS LANGUAGE。如果在模型的自然演变过程中模型的定义也发生改变,那么就要修改模型名称了。
很多对象模型都有文献资料可查,其中有些对象模型专门用于某个行业中的某种应用,而有些则是通用模型。大部分对象模型都有助于开阔思路,但只有为数不多的一些模型精辟地阐述了选择这些模式的原理和使用的结果,而这些才是分析模式的精华所在。这些精化后的分析模式大部分都很有价值,有了它们,可以免去一次次的重复开发工作。尽管我们不大可能归纳出一个包罗万象的分析模式类目,但针对具体行业的类目还是能够开发出来的。而且在一些跨越多个应用的领域中适用的模式可以被广泛共享。
这种对已组织好的知识的重复利用完全不同于通过框架或组件进行的代码重用,但是二者唯一的共同点是它们都提供了一种新思路的萌芽,而这种新思路先前可能并不十分明晰。一个模型,甚至一个通用框架,都是一个完整的整体,而分析则相当于一个工具包,它被应用于模型的一些部分。分析模式专注于一些最关键和最艰难的决策,并阐明了各种替代和选择方案。它们提前预测了一些后期结果,而如果单靠我们自己去发现这些结果,可能会付出高昂的代价。

将设计模式应用于模型

设计模式(design pattern)——设计模式是对一些互相交互的对象和类的描述,我们通过定制这些对象和类来解决特定上下文中的一般设计问题[Gamma et al. 1995, p. 3]。
到目前为止,本书所探讨的模式都是专门用来在MODEL-DRIVEN DESIGN的上下文中解决领域模型的问题。但实际上,大部分已发布的模式都更侧重于解决技术问题。设计模式与领域模式之间有什么区别?《设计模式》这部经典著作的作者为初学者指出了以下事实[Gamma et al. 1995, p. 3]:
立场不同会影响人们如何看待什么是模式以及什么不是模式。一个人所认为的模式在另一个人看来可能是基本构造块。本书将在一定的抽象层次上讨论模式。设计模式并不是指像链表和散列表那样可以被封装到类中并供人们直接重用的设计,也不是用于整个应用程序或子系统的复杂的、领域特定的设计。本书中的设计模式是对一些交互的对象和类的描述,我们通过定制这些对象和类来解决特定上下文中的一般设计问题。
在《设计模式》中,有些(但并非所有)模式可用作领域模式,但在这样使用的时候,需要变换一下重点。《设计模式》中的设计模式把相关设计元素归为一类,这些元素能够解决在各种上下文中经常遇到的问题。这些模式的动机以及模式本身都是从纯技术角度描述的。但这些元素中的一部分在更广泛的领域和设计上下文中也适用,因为这些元素所对应的基本概念在很多领域中都会出现。
除了《设计模式》中介绍的模式以外,近年来还出现了其他很多技术设计模式。有些模式反映了在一些领域中出现的深层概念。这些模式都有很大的利用价值。为了在领域驱动设计中充分利用这些模式,我们必须同时从两个角度看待它们:从代码的角度来看它们是技术设计模式,从模型的角度来看它们就是概念模式
我们将把《设计模式》所介绍的特定模式作为样例,来说明如何将人们所认为的设计模式应用到领域模型中,而且这个例子还将澄清技术设计模式与领域模式之间的区别。本章还将通过COMPOSITE(组合)和STRATEGY(策略)这两种模式演示如何通过改变思考方式,用一些经典的设计模式来解决领域问题。

模式:STRATEGY(也称为POLICY)

请添加图片描述

领域模型包含一些并非用于解决技术问题的过程,将它们包含进来是因为它们对处理问题领域具有实际的价值。当必须从多个过程中进行选择时,选择的复杂性再加上多个过程本身的复杂性会使局面失去控制。
当对过程进行建模时,我们经常会发现过程有不止一种合理的实现方式,而如果把所有的可选项都写到过程的定义中,定义就会变得臃肿而复杂,而且可供我们选择的实际行为也会因为混杂在其他行为中而显得模糊不清。
我们希望把这些选择从过程的主体概念中分离出来,这样既能够看清主体概念,也能更清楚地看到这些选择。软件设计社区中众所周知的STRATEGY模式就是为了解决这个问题的,虽然它的侧重点在于技术方面。这里,我们把它当成模型中的一个概念来使用,并在该模型的代码实现中把它反映出来。我们同样也需要把过程中极易发生变化的部分与那些更稳定的部分分离开。
我们需要把过程中的易变部分提取到模型的一个单独的"策略"对象中。将规则与它所控制的行为区分开。按照STRATEGY设计模式来实现规则或可替换的过程。策略对象的多个版本表示了完成过程的不同方式。
通常,作为设计模式的STRATEGY侧重于替换不同算法的能力,而当其作为领域模式时,其侧重点则是表示概念的能力,这里的概念通常是指过程或策略规则。
我们在领域层中使用技术设计模式时,必须认识到这样做的另外一种动机,也是它的另一层含义。当所使用的STRATEGY对应于某种实际的业务策略时,模式就不再仅仅是一种有用的实现技术了(但它在实现方面的价值并未改变)。
设计模式的结论也完全适用于领域层。例如,在《设计模式》一书中,Gamma等人指出客户必须知道不同的STRATEGY,这也是建模的一个关注点。如果单纯从实现上来考虑,使用策略可能会增加系统中对象的数目。如果这是个问题,可以把STRATEGY实现为无状态对象,以便在上下文中进行共享,从而减小开销。《设计模式》中对实现方法的全面讨论在这里也适用,这是因为我们仍然在使用STRATEGY,只是动机稍有不同,这会对我们的选择产生一些影响,但设计模式中的经验仍然是可以借鉴的。

模式:COMPOSITE

请添加图片描述

在对复杂的领域进行建模时,我们经常会遇到由多个部分组成的重要对象,这些部分本身又由其他一些部分组成,依此类推,有时甚至会出现任意深度的嵌套。在一些领域中,各层嵌套在概念上是有区别的,但在另一些领域中,各个部分与它们所组成的整体是完全相同的事物,只是规模较小一些而已。
当嵌套容器的关联性在模型中没有反映出来时,公共行为必然会在层次结构的每一层重复出现,而且嵌套也变得僵化(例如,容器通常不能包含同一层中的其他容器,而且嵌套的层数也是固定的)。客户必须通过不同的接口来处理层次结构中的不同层,尽管这些层在概念上可能没有区别。通过层次结构来递归地收集信息也变得非常复杂。
**当在领域中应用任何一种设计模式时,首先关注的问题应该是模式的意图是否确实适合领域概念。**以递归的方式遍历一些相互关联对象确实比较方便,但它们是否真的存在整体—部分层次结构?你是否发现可以通过某种抽象方式把所有部分都归到同一概念类型中?如果你确实发现了这种抽象方式,那么使用COMPOSITE可以令模型的这些部分变得更清晰,同时使你能够借助设计模式所提供的那些经过深思熟虑的设计及实现的考量。
定义一个把COMPOSITE的所有成员都包含在内的抽象类型。在容器上实现那些查询信息的方法时,这些方法返回由容器内容所汇总的信息。而"叶"节点则基于它们自己的值来实现这些方法。客户只需使用抽象类型,而无需区分"叶"和容器。
相对而言,这是一种明显的结构层面上的模式,但设计人员通常不会主动地充实它的操作方面。COMPOSITE模式在每个结构层上都提供了相同的行为,而且无论是较小的部分还是较大的部分,都可以对这些部分提出一些有意义的问题,这些问题能够透明地反映出它们的构成情况。这种严格的对称是组合模式具有强大能力的关键所在。
设计模式应该仅仅在需要的时候才使用。

为什么没有介绍FLYWEIGHT

FLYWEIGHT虽然是设计模式的一个典型的例子,却并不适用于领域模型。
当一个VALUE OBJECT集合(其中的值对象数目有限)被多次使用的时候(如房屋规划中电源插座的例子),那么把它们实现为FLYWEIGHT可能是有意义的。这是一个适用于VALUE OBJECT(但不适用于ENTITY)的实现选择。COMPOSITE模式与它的不同之处在于,组合模式的概念对象是由其他概念对象组成的。这使得组合模式既适用于模型,也适用于实现,这是领域模式的一个基本特征。
本文并不打算把那些可以当作领域模式使用的设计模式完整地列出来。虽然没有一个把"解释器"(interpreter)用作领域模式的例子,但也不能断言解释器不适用于任何一种领域概念。把设计模式用作领域模式的唯一要求是这些模式能够描述关于概念领域的一些事情,而不仅仅是作为解决技术问题的技术解决方案。

参考

《领域驱动设计 软件核心复杂性应对之道》 Eric Evans 著, 赵俐 盛海艳 刘霞 等译, 任发科 审校

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2074643.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Puppeteer Web 抓取:使用 Browserless 的 Docker

Docker 镜像介绍 Docker 镜像是用于在 Docker 容器中执行代码的文件。它类似于构建 Docker 容器的指令集,就像一个模板。换句话说,它们相当于虚拟机环境中的快照。 Docker 镜像包含运行容器所需的所有库、依赖项和文件,使其成为容器的独立可…

虚拟机Ubuntu误操作导致无法自动联网的解决办法

直接上解决办法:安装netplan.io。 sudo apt install netplan.io sudo netplan apply 问题描述: 虚拟机的Ubuntu由于我的乱操作不小心删除了很多东西,导致开机无法自动联网了。而且在设置里边也没了设置网络的地方。 尝试不同办法发现用sudo…

基于javaweb+jsp的鲜花商城系统

基于javawebjsp的鲜花商城系统的设计与实现~ 开发语言:Java 数据库:MySQL 技术:SpringSpringMVCMyBatisJSP 工具:IDEA/Ecilpse、Navicat、Maven 系统展示 前台 后台 摘要 当下,正处于信息化的时代,许多行…

超越GPT4V,最强多模态MiniCPM-V2.6模型分享

MiniCPM-V2.6是由OpenBMB开发的一款多模态大型语言模型(MLLM),专为视觉-语言理解设计。 MiniCPM-V2.6模型能够处理图像、视频和文本输入,并提供高质量的文本输出。 MiniCPM-V 2.6模型在单图像理解方面超越了广泛使用的专有模型&…

78 Linux libusb库USB HID应用编程笔记

1 前言 这几天搞另外一个项目,基于Ubuntu开发一个小的应用程序,就是通过USB HID与设备通信。因此需要在Linux环境编写对应USB HID通信应用。 目前libusb库已经很好的支持USB相关应用的开发,库中提供了丰富的USB接口,用户可以直接调…

gptk是什么意思?Mac电脑如何在crossover里安装gptk2.0测试版?借助GPTK玩《原神》《黑神话悟空》游戏

很人多都听说使用 gptk2.0 beta 可以让《黑神话:悟空》等游戏的帧数提高,但自己并不知道如何安装,下面就给大家说下如何在crossover里安装 gptk2.0 beta 。安装前请先确认自己的电脑里已经安装好了crossover软件。 Game Porting Toolkit 简介…

【MySQL】MySQL表的增删改查(初阶)

欢迎关注个人主页:逸狼 创造不易,可以点点赞吗~ 如有错误,欢迎指出~ 目录 表内容操作 插入内容 按顺序插入 指定某些列插入 一次插入多行记录 插入时间 查询表内容 全列查询 指定列查询 指定表达式查询 用as取别名 ​编辑 去重查询 排序查询…

堆排序算法及优化(java)

目录 1.1 引言 1.2 堆排序的历史 1.3 堆排序的基本原理 1.3.1 堆的概念 1.3.2 堆排序的过程 1.3.3 堆调整 1.3.4 堆排序算法流程 1.4 堆排序的Java实现 1.4.1 简单实现 1.4.2 代码解释 1.4.3 优化实现 1.4.4 代码解释 1.5 堆排序的时间复杂度 1.5.1 分析 1.5.2 …

Flutter ListView滑动

在Flutter中,ScrollController可以精确地控制和管理滚动行为。通过ScrollController,可以监听滚动的位置、速度,甚至可以在用户滚动时触发自定义的动作。此外,ScrollController还提供了对滚动位置的直接控制,可以编程地…

Aiseesoft PDF Converter Ultimate 3.3.62 + crack

Aiseesoft PDF Converter Ultimate 是一个用于将 PDF 文件转换为其他格式的程序。它允许您将 PDF 转换为 Word、Text、Excel、PowerPoint、ePub、HTML、JPG、TIFF、PNG、GIF 等。 以下是该程序主要功能的简要说明: 支持不同的格式。该程序支持超过 25 种不同的格式,用于从 P…

PyTorch深度学习网络(一:MLP)

全连接神经网络,又称多层感知机(MLP),是深度学习最基础的神经网络。全连接神经网络主要由输入层、隐藏层和输出层构成。本文实现了一个通用MLP网络,包括以下功能: 根据输入的特征数、类别数、各隐藏层神经…

Canvas 动画: atan2 三角函数与鼠标跟随效果

这个案例展示了如何使用HTML5的Canvas和JavaScript实现一个动态效果:在画布上绘制一个箭头,并让它实时跟随鼠标移动。这个小项目不仅有趣,还能帮助你理解编程和基本数学概念的实际应用。 项目需求 我们的目标是在一个画布上绘制一个箭头&…

java-4 final、单例类、枚举类、抽象类、接口

final 1. 认识final 2. 常量 大项目中经常将常量集中写在Constant文件中 单例类 (设计模式) 为什么要把构造器私有化,你不是私有化,别人就可以 new 好多个对象,还怎么是单例吖 定义一个类变量、类方法,…

海外媒体宣发:著名媒体【越南通讯社VNanet】发布新闻稿

海外媒体宣发:著名媒体【越南通讯社VNanet】发布新闻稿 近日,越南通讯社VNanet发布了一篇关于全球气候变化的新闻稿,引起了广泛关注。本文将详细介绍新闻稿的主要内容以及其对全球气候变化的影响。 一、新闻稿概述 越南通讯社VNanet作为越…

解决WIndows10下更新蓝牙驱动屡屡失败问题

因为换了个1T自带Win10系统的SSD硬盘,导致蓝牙驱动死活装不上了。驱动精灵,官方驱动都没用。这可前所未闻啊。 想起换下来的硬盘系统里面还有系统在,试试看能不能直接用之前的系统蓝牙驱动,原则上是应该没问题的。所以就将之前的…

混合现实UI优化:利用物理环境的直接交互

随着虚拟现实(VR)和混合现实(MR)技术的发展,用户界面(UI)的设计变得越来越重要,尤其是在需要适应多种物理环境的情况下。本文将介绍一种名为 InteractionAdapt 的用户界面优化方法,它专为VR环境中的工作空间适配而设计,能够有效利用物理环境,为用户提供更加灵活和个…

Kafka的Offset(偏移量)详解

Kafka的Offset详解 1、生产者Offset2、消费者Offset2.1、消费者2.2、生产者2.3、实体类对象2.4、JSON工具类2.5、项目配置文件2.6、测试类2.7、测试2.8、总结 1、生产者Offset 2、消费者Offset 2.1、消费者 package com.power.consumer;import org.apache.kafka.clients.consu…

Android - 自定义view

为什么要自定义view? 在Android开发中有很多业务场景,原生的控件无法满足需求,并且经常也会遇到一个UI在多处重复使用情况,于是可以通过自定义View的方式来实现这些UI效果。 自定义view的分类 自定义属性 Window window是一个…

图数据库查询语言 cypher 与 memgraph

Cyper 作为声明式查询语言, SQL 在计算机行业无人不晓, 无人不知. 而 Cypher 就是 Graph Database 图数据库的 SQL. Cypher 用"圆括号"来表示节点, 用"方括号,连接线及箭头"表示关系 这样一句话 - "Sally likes Graphs. Sally is friends with John. …

完成控制器方法获取参数-@RequestParam

文章目录 1.将方法的request和response参数封装到参数数组1.SunDispatcherServlet.java1.根据方法信息,返回实参列表2.具体调用 2.测试 2.封装Http请求参数到参数数组1.自定义RequestParam注解2.MonsterController.java 增加参数3.SunDispatcherServlet.java1.resol…