F#奇妙游(25):ADT和领域设计

这篇具有很好参考价值的文章主要介绍了F#奇妙游(25):ADT和领域设计。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

采用ADT来对领域进行设计,是一种很好的实践。在这种实践中,我们可以把领域中的数据抽象成ADT,把领域中的操作抽象成函数,然后利用ADT的类型系统来进行类型检查,从而保证领域中的数据和操作的正确性。

设计目标

首先,我们的设计目标如下:

  1. 各领域专家架和程序开发都能够理解的设计
  2. 能够利用ADT的类型系统来进行类型检查
  3. 不需要与具体的编程语言乃至编程范式绑定

设计原则

那么我们需要遵循大概以下的原则:

  1. 描述ADT的术语应该尽量与领域中的术语一致
  2. 描述ADT的数据结构应该尽量与领域中的数据结构一致
  3. 描述ADT的操作应该尽量与领域中的操作一致
  4. ADT的分析应该专注于组合而不是继承
  5. ADT的各个组合部分都应该都领域含义,而非编程语言的实现细节
  6. 编程实现的细节(例如基本数据类型、数据结构和算法的实现)在设计阶段应该被忽略

软件开发流程

从本质上来看,所有的设计都应该是迭代的。不过我们还是可以首先给出一个线性的流程,然后再给出检查点,并定义迭代的流程。

首先是整个软件系统开发的流程,如果我们非常丧心病狂,并且非常注重完备性,务必要把所有的步骤都走一遍,那么整个流程如下:

如果我们把编程实现、测试和部署抽象为系统实现,那么这个图会稍微好看一点。

当我们暂时把系统实现扔掉,那么整个流程就是:

领域分析

领域驱动设计中,领域分析的核心内容系统的事件分析,一般会采用事件风暴(Event Storming)的方法来进行。在这个过程中,我们会把领域中的事件抽象为事件(Event),把事件中的数据抽象为值对象(Value Object),把事件中的操作抽象为实体(Entity)。

并进一步考虑事件的触发条件或者触发事件,以及事件的结果,这些都是领域中的事件,但是不是所有的事件都是我们需要关注的,我们只需要关注那些对我们的系统有意义的事件。这个过程最重要的原则就是,到底到边。

一直要事件的分析推到系统的边界上,或者是某个Actor的动作触发了事件,或者某个状态触发了事件,而事件的发生又会改变系统的状态,或者触发另外的事件。这其中比较重要的就是对现存系统的分析,以及对现存系统的边界的分析。

当通过事件风暴把系统的事件分析完毕之后,需要的就是进行事件的分类、排序,分析触发事件的命令,把一系列事件组合起来,形成一个个有逻辑的序列,在这个基础上,可进行子领域的划分,以及子领域之间的关系的分析。每个子领域应该对应特定的领域专家,或者是特定的团队,这样可以保证领域专家的专业性,也可以保证团队的独立性。

事件的内涵外延、相互关系定义取得领域专家的一致意见后,需要领域专家进一步分析事件的输入和输出,事件的输入和输出就是事件的数据,这些数据可以是值对象,也可以是实体。这个过程中,需要领域专家对事件的输入和输出进行分析,然后把这些数据抽象为值对象或者实体。

所以领域分析大概内容就是事件分析、命令与业务流程、子领域与上下文等。

进一步ADT分析与设计,就可以形式化描述领域共享模型。

领域流程ADT

根据前面的分析,领域的模型由命令、事件和业务流程构成,并形成子领域、有界上下文,最终能够捕捉领域中的值的流动和业务信息。

在这个领域模型的核心,是信息传递和传唤的过程。这个过程可能称为流程、操作这类动词。在F#这类函数式编程中,则用函数来表达。

这里三个元素:合法的输入集合、函数、合法的输出集合,都可以抽象为一个抽象数据类型(ADT),而ADT的组合数,就对应着输入输出的合法性以及函数对应关系。

这个样子,领域流程或者操作的编程对应就非常清楚,同样是一个ADT,可以表达为 A D T 1 ↦ A D T 2 ADT_1 \mapsto ADT_2 ADT1ADT2

所以领域的流程、流程的输入输出对应就是进行ADT设计,而对ADT的组合数则可用于实现关于合法的相关约束,这样才能做到非法状态不可表示。

ADT设计

ADT设计的核心就是对领域中的数据和操作进行抽象,这个过程中,我们需要把领域中的数据抽象为值对象或者实体,并用ADT来描述;并把领域中的操作抽象为ADT映射(同样是一个ADT)。

在ADT设计中,F#能提供什么支持呢?根据前面ADT的分析和学习,我们知道,ADT的两种基本形式就是Sum和Product。

Sum类型是OR的关系,Product类型是AND的关系。对领域中的值、表达式进行描述时,如果采用OR和AND来表示,大概会是:

data InputData = DataID
    AND DataField1
    AND DataFiled2
    AND DataFiled3
data DataID = DataName
    OR DataSerialNumber

上面这样的描述,可以将值的类型表达为领域专家所能够理解的形式,输入数据包括标识和数个字段;输入数据的标识可能是字符串也可能是序列号。

从前面ADT的分析和介绍看,组合数分析是非常总要的。因此,对于ADT中所包含的类型,需要进一步根据领域情况分析。例如

data DataName of string 
    length in 12..255
    ascii a..z, A..Z, 0..9
    first 8 chars: valid date string
    ex. 20230830xxxx
data DataSerialNumber of int
    12 digits
    first 8 digits: valid date string
    last 4 digits: serial number 0..9999
    ex. 202308301234

上面的信息,足够分析DataName的组合数。通过这样的分析和记录,就能够很好的搞清楚领域中的信息,并记录为整个团队都能很好理解的形式。

在领域分析和设计的阶段,并不需要专注于特定的语法和开发语言,关键是要清晰地分析和表达各个值的类型,要清晰到能够分析组合数的程度。文章来源地址https://www.toymoban.com/news/detail-689780.html

结论

  1. 领域分析可以采用领域的语言和领域的知识来完成,领域、子领域、上下文;
  2. 领域建模的核心就是把领域的数据、流程(输入输出和映射)描述为对应的ADT;
  3. F#等函数式编程工具通过对ADT的支持,提供了领域模型的绝佳对应,非常适合用于领域驱动开发。

到了这里,关于F#奇妙游(25):ADT和领域设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Rust编程语言入门之函数式语言特性:-迭代器和闭包

    闭包(closures) 迭代器(iterators) 优化改善 12 章的实例项目 讨论闭包和迭代器的运行时性能 闭包:可以捕获其所在环境的匿名函数。 闭包: 是匿名函数 保存为变量、作为参数 可在一个地方创建闭包,然后在另一个上下文中调用闭包来完成运算 可从其定义的作用域捕获值

    2023年04月08日
    浏览(46)
  • 编程语言MoonBit新增矩阵函数的语法糖

    1. 新增矩阵函数的语法糖 新增矩阵函数的语法糖,用于方便地定义局部函数和具有模式匹配的匿名函数: 2. 新增使用 T::{ ... } 构造结构体的语法 这个新语法可用于显式的指定结构体的类型,并会使得结构体内有更好的补全: 3. 正式移除 var id = expr 的语法 4. 增加了新的关键

    2024年01月23日
    浏览(47)
  • 函数探秘:深入理解C语言函数,实现高效模块化编程

    ✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C语言学习 贝蒂的主页:Betty‘s blog 在数学中我们就知道了函数这个概念,而C语言同样引入了函数这个概念,那C语言的函数到底是什么样的呢? 在C语言中, 函数也叫子程序,它是一段可以

    2024年03月09日
    浏览(70)
  • 掌握Go语言:Go语言递归函数,解密编程之谜,探索算法的奥秘!(27)

    递归函数是指在函数内部调用自身的函数。在Go语言中,递归函数使用起来非常方便,但需要注意递归的终止条件,以避免无限循环。 Go语言递归函数的使用方法 在Go语言中,编写递归函数的基本步骤如下: 上述三点内容详细解释如下: 定义一个函数,函数内部调用自身 :

    2024年04月15日
    浏览(55)
  • 模拟计算器编程教程,中文编程开发语言工具编程实例

    模拟计算器编程教程,中文编程开发语言工具编程实例 中文编程系统化教程,不需英语基础。学习链接 ​​​​​​https://edu.csdn.net/course/detail/39036 课程安排:初级1 1  初级概述 2  熟悉构件取值赋值 3 折叠式菜单滑动面板编程 4 自定义图形窗口自定义标题栏编程 5 多行文本

    2024年02月08日
    浏览(67)
  • 什么是栈,为什么函数式编程语言都离不开栈?

    ​ 栈是一种具有特殊访问方式的存储空间,它的特殊性在于, 最后进入这个空间的数据,最先出去 ,可以画图来描述一下这种操作方式。 假设有一个盒子和三本书,依次将三本书他们放入盒子中。 入栈模拟图 ​ 现在有一个问题,如果一次只能取一本,我们如何将书从盒子

    2024年02月06日
    浏览(70)
  • Hlang--用Python写个编程语言-函数与基本数据结构实现

    okey,经过一段时间的努力,接下来要实现的是函数。当然还有对应的基本数据结构,那么之后的话,我们的工作就开始进一步转换了。 那么在这块我们要实现的有: 函数的定义 String类型的实现 列表类型的实现 实话实话,这个的实现是相当简陋的。不过作为一个小模型,应该

    2024年02月12日
    浏览(60)
  • 中文编程开发语言工具构件说明:屏幕截取构件的编程操作

    屏幕截取 用于截取指定区域的图像。 图    标: 构件类型:不可视 重要属性 l        截取类型 枚举型,设置在截取屏幕时的截取类型。包括:全屏幕、指定区域、活动窗口三种。当全屏幕截取时相当于执行了硬拷屏(PrintScreenSysRq键)功能;指定区域截取则是通过矩形

    2024年02月07日
    浏览(57)
  • APP开发入门:了解主流的编程语言

    在过去的几年里,有许多程序员开始学习和使用编程语言。这其中包括C、C++、 Java和 Python。尽管有许多语言可供选择,但大多数程序员都会选择最容易学习的编程语言。 如今,有很多编程语言供选择。程序员们在学习这些语言时可以自由地选择他们喜欢的方式,因为他们的

    2024年02月15日
    浏览(49)
  • 【跟小嘉学 Rust 编程】十三、函数式语言特性:迭代器和闭包

    【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学 Rust 编程】六、枚举

    2024年02月11日
    浏览(60)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包