领域驱动设计(DDD)【22】之限定建模技术

文章目录

  • 一 限定初识
  • 二 限定识别
  • 三 限定实现

一 限定初识

  • 一个 员工 可以拥有多份 工作经验,而各个 工作经验时间段 不能相互重叠。可以得出一个推论:对于一个 员工 而言,每个 时间段 只能有一条 工作经验
    在这里插入图片描述

  • UML中第二种表述方式,如下图:
    在这里插入图片描述

  • 标有“: 时间段”的方框,叫做“限定符”(qualifier)。

  • 对于一个员工,任何一个时间段,要么没有工作经验,要么有一条工作经验,但不能有多条工作经验。换句话说,一个员工可以有多条工作经验,但限定在一个时间段的话,那么最多就只能有一条工作经验。

  • 限定机制起到两个作用:第一,表达了更丰富的语义,把原来用注解说明的约束变成了更严格的符号;第二,简化了关联关系的多重性,把原来的一对多,在形式上,变成了一对一。

二 限定识别

在这里插入图片描述

  • 在技能实体上,原来有一个“同一技能不能录入两次”的约束。现在由于增加对技能类别的限定,已经表达相同的意思。

  • 项目和项目成员之间的关联,是否应该使用限定呢?
    在这里插入图片描述
  • 虽然项目成员里面也有时间段属性,但是项目和项目成员之间的关联并没有被时间段所限定。因为即使在同一个时间段,一个项目还是可以有多个成员。
  • 尽管项目经理和项目成员中都有时间段,但项目经理的关联被时间段所限定了,而项目成员则没有。现在的表示方法清楚地体现出了两者之间的这种区别,而之前只能通过注释中的文字来表达。

  • 项目成员“不必”用时间段来限定,而不是“不能”限定。这是因为,理论上其实也可以在项目一端加一个时间段限定。最终效果如下:
    在这里插入图片描述

三 限定实现

  • 以工作经验(work_experience)表和技能(skill)进行“限定”在数据库里的实现。通过添加唯一索引,在工作经验表上体现出时间段的限定,并且在技能表上体现出技能类别的限定。
    在这里插入图片描述
// domain.orgmng.emp;
//imports ...
public class Emp extends AggregateRoot {// other fields ...// protected List<Skill> skills = new ArrayList<>();protected Map<Long, Skill> skills = new HashMap<>();// protected List<WorkExperience> experiences;protected Map<Period, WorkExperience> experiences = new HashMap<>();// other methods...public Collection<Skill> getSkills() {// return Collections.unmodifiableList(skills);return Collections.unmodifiableCollection(skills.values());}public Optional<Skill> getSkill(Long skillTypeId) {// return skills.stream()//         .filter(s -> s.getSkillTypeId().equals(skillTypeId))//         .findAny();return Optional.ofNullable(skills.get(skillTypeId));}public void addSkill(Long skillTypeId, SkillLevel level, int duration, Long userId) {skillTypeShouldNotDuplicated(skillTypeId);Skill newSkill = new Skill(tenantId, skillTypeId, userId).setLevel(level).setDuration(duration);//skills.add(newSkill);skills.put(skillTypeId, newSkill);}private void skillTypeShouldNotDuplicated(Long newSkillTypeId) {// if (skills.stream().anyMatch(//            s -> s.getSkillTypeId().equals(newSkillTypeId))) {if (skills.get(newSkillTypeId) != null) {throw new BusinessException("同一技能不能录入两次!");}}//    public List<WorkExperience> getExperiences() {//        return Collections.unmodifiableList(experiences);//    }public Collection<WorkExperience> getExperiences() {return Collections.unmodifiableCollection(experiences.values());}public void addExperience(Period period, String company, Long userId) {durationShouldNotOverlap(period);WorkExperience newExperience = new WorkExperience(tenantId, period, LocalDateTime.now(), userId).setCompany(company);//experiences.add(newExperience);experiences.put(period, newExperience);}private void durationShouldNotOverlap(Period newPeriod) {// if (experiences.stream().anyMatch(//                 e -> e.getPeriod().overlap(newPeriod))) {if (experiences.values().stream().anyMatch(e -> e.getPeriod().overlap(newPeriod))) {throw new BusinessException("工作经验的时间段不能重叠!");}}// other methods...
}
  • 把Emp类的skills属性的类型改成Map。Map的Key实际就是 技能类别ID,就保证了对 技能类别 所限定的唯一性。
  • getSkills() 方法,我们取了Map的 values(),并把方法的返回值类型改成了Collection。
  • getSkill(Long skillTypeId) 方法,我们直接从 Map 里取值,而不是像以前那样通过遍历 List 来搜索。
  • 当写程序的时候,如果发现从 List 里搜索比较麻烦,可能就已经想到改成 Map 了。我们就可以“反推”出模型中很可能应该使用限定。这其实是在编写代码的过程中,以优化代码结构为启发,反过来促使模型演进的一个例子。

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

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

相关文章

《P6492 [COCI 2010/2011 #6] STEP》

题目描述 给定一个长度为 n 的字符序列 a&#xff0c;初始时序列中全部都是字符 L。 有 q 次修改&#xff0c;每次给定一个 x&#xff0c;若 ax​ 为 L&#xff0c;则将 ax​ 修改成 R&#xff0c;否则将 ax​ 修改成 L。 对于一个只含字符 L&#xff0c;R 的字符串 s&#…

macOS,切换 space 失效,向右切换space(move right a space) 失效

背景 准确来讲&#xff0c;遇到的问题是向右切换space&#xff08;move right a space) 失效&#xff0c;并向左是成功的。 在键盘-快捷键-调度中心中&#xff0c;所有的快捷键均可用&#xff0c;但是“向右移动一个空间”总是失效。 已经检查过不是快捷键冲突的问题&#x…

网飞猫官网入口 - 免费高清影视平台,Netflix一站观看

网飞猫是一个专注于提供丰富影视资源的在线平台&#xff0c;涵盖国内外热门电影、电视剧、动漫、综艺等多种类型。它不仅整合了Netflix的独家内容&#xff0c;还提供了大量高清、蓝光画质的影视作品&#xff0c;支持多语言字幕&#xff0c;满足不同用户的观影需求。网飞猫的界面…

Hyper-v-中的FnOs--飞牛Nas虚拟磁盘扩容(不清除数据)

在Hyper-v下的飞牛Nas要怎么在不删除原有虚拟磁盘数据的情况下扩容呢 OK下面开始教学&#xff08;适用于Basic模式的虚拟磁盘扩容&#xff0c;Linear没试过&#xff09; 先关闭飞牛Nas系统 找到飞牛Nas虚拟机&#xff0c;在设置下SCSI控制器找到要扩容的虚拟磁盘&#xff0c; 点…

掌握 MySQL 的基石:全面解读数据类型及其影响

前言 上篇文章小编讲述了关于MySQL表的DDL操作&#xff0c;在那里我多次使用了MySQL的数据类型&#xff0c;但是我并没有去讲述MySQL的数据类型&#xff0c;想必各位读者已经很好奇MySQL的数据类型都有什么了&#xff0c;今天这篇文章我将会详细的去讲述MySQL的数据类型&#x…

buildadmin 如何制作自己的插件

官方文档指引 提示&#xff1a;若不计划发布到应用市场&#xff0c;可省略图片等非必要功能 参考文档&#xff1a;https://doc.buildadmin.com/senior/module/basicInfo.html 目录 官方文档指引开发说明模块开发流程模块包结构示例安装开发工具 总结 开发说明 目标&#xff…

【数据标注师】关键点标注

目录 一、 **关键点标注的四大核心原则**二、 **五阶能力培养体系**▶ **阶段1&#xff1a;基础认知筑基&#xff08;1-2周&#xff09;**▶ **阶段2&#xff1a;复杂场景处理技能▶ **阶段3&#xff1a;三维空间标注&#xff08;进阶&#xff09;**▶ **阶段4&#xff1a;效率…

创建网站的基本步骤?如何建设自己的网站?

创建网站是一个系统化的过程&#xff0c;涵盖规划、设计、开发、测试和发布等多个阶段。以下是详细步骤及关键工具推荐&#xff1a; 一、规划阶段&#xff1a;明确目标与内容 定义目标 1、确定网站目的&#xff08;展示信息、销售、博客、服务等&#xff09;。 2、分析目标…

FreeSWITCH配置文件解析(2) dialplan 拨号计划中xml 的action解析

在 FreeSWITCH 的拨号计划&#xff08;Dialplan&#xff09;中&#xff0c;使用 XML 配置。其中&#xff0c;<action> 标签用于指定要执行的操作。这些操作通常是应用程序&#xff08;applications&#xff09;或设置变量等。下面列出常见的 <action> 类型及其含义…

MCPA2APPT:基于 A2A+MCP+ADK 的多智能体流式并发高质量 PPT 智能生成系统

&#x1f680; MCPA2APPT / MultiAgentPPT 集成 A2A MCP ADK 架构的智能化演示文稿生成系统&#xff0c;支持多智能体协作与流式并发&#xff0c;实时生成高质量 PPT 内容。 &#x1f9e0; 项目简介 MultiAgentPPT&#xff08;又名 MCPA2APPT&#xff09;采用 A2A&#xff…

Maven 多模块项目调试与问题排查总结

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

debian国内安装docker

先升级apt和安装依赖包 apt update apt upgrade apt install curl vim wget gnupg dpkg apt-transport-https lsb-release ca-certificates添加存储库的GPG密钥&#xff08;阿里云&#xff09; curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | sudo gpg…

vue网页中的一个天气组件使用高德api

今天写了一个天气组件效果如下&#xff1a; 实现代码如下&#xff1a; <template><div><span click"getLocation" style"cursor: pointer"><span style"color:white;">{{ weatherInfo.area }}</span></span&g…

5 手写卷积函数

5 手写卷积函数 背景介绍滑动窗口的方式代码问题 矩阵乘法的方式原理代码结果 效果对比对比代码日志结果 一些思考 背景 从现在开始各种手写篇章&#xff0c;先从最经典的卷积开始 介绍 对于卷积层的具体操作&#xff0c;我这里就不在具体说卷积具体是什么东西了。 对于手写…

vue3+element-plus,实现两个表格同步滚动

需求&#xff1a;现在需要两个表格&#xff0c;为了方便对比左右的数据&#xff0c;需要其中一边的表格滚动时&#xff0c;另一边的表格也跟着一起滚动&#xff0c;并且保持滚动位置的一致性。具体如下图所示。 实现步骤&#xff1a; 确保两个表格的宽度一致&#xff1a;如果两…

Mysql架构

思考&#xff1a;Mysql需要重点学习什么&#xff1a; 索引&#xff1a;索引存储结构、索引优化......事务&#xff1a;锁机制与隔离级别、日志、集群架构 本文是对Mysql架构进行初步学习 1、Mysql链接 Mysql监听器是长连接 BIO(阻塞同步IO调用)&#xff0c; 不是NIO. 为什么…

使用deepseek制作“喝什么奶茶”随机抽签小网页

教程很简单&#xff0c;如下操作 1. 新建文本文档&#xff0c;命名为奶茶.txt 2. 打开deepseek&#xff0c;发送下面这段提示词&#xff1a;用html5帮我生成一个喝什么奶茶的网页&#xff0c;点击按钮随机生成奶茶品牌等&#xff0c;包括喜茶等众多常见的奶茶品牌如果不满意还…

WOE值:风险建模中的“证据权重”量化术——从似然比理论到FICO评分卡实践

WOE值&#xff08;Weight of Evidence&#xff0c;证据权重&#xff09; 是信用评分和风险建模中用于量化特征分箱对目标变量的预测能力的核心指标。 本文由「大千AI助手」原创发布&#xff0c;专注用真话讲AI&#xff0c;回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关…

js递归性能优化

JavaScript 递归性能优化 递归是编程中强大的技术&#xff0c;但在 JavaScript 中如果不注意优化可能会导致性能问题甚至栈溢出。以下是几种优化递归性能的方法&#xff1a; 1. 尾调用优化 (Tail Call Optimization, TCO) ES6 引入了尾调用优化&#xff0c;但只在严格模式下…

vue界面增加自定义水印 js

vue整个界面增加自定义水印 需求&#xff1a;领导想要增加自定义水印 好不容易调完&#xff0c;还是想记录一下,在.vue界面编写 export default {mounted() {this.$nextTick(() > {this.addWatermark()})},methods: {// 关键&#xff1a;添加水印// 动态添加水印addWaterm…