【架构师成长之领域驱动开发】

架构师成长之路

  • 1. 如何构建高质量应用?
  • 2. 三大设计原则?
  • 3.DDD妙招
  • 4. 最终的改造结果
  • 5.模型

项目中的“坏”味道

  1. 可维护性差:大量的第三方模块影响核心代码的稳定性
  2. 可扩展性差:业务逻辑与数据存储相互依赖,无法复用
  3. 可测试性差:庞大事务脚本与基础设施强耦合,无法单元测试。
    最后的结果:业务发生几次迭代后,这段代码就将成为一个可怕的黑洞。

1. 如何构建高质量应用?

高内聚、低耦合

2. 三大设计原则?

  1. 单一职责原则:一个类只负责单一职责,另一种理解也就是一个类应该只有一个引起它变化的原因。
  2. 开放封闭原则: 对扩展开放,对修改关闭。
  3. 依赖反转原则:程序之间应该只只依赖于抽象接口,而不要依赖于具体实现(java特性-多态体现)。

3.DDD妙招

  1. 使用充血模型的实体对象,描述核心业务能力。

系统能做什么事情,一目了然。

public class Account {private Long id;private Long accountNumber;private BigDecimal available;public void withdraw() {// 转入操作available = abailable + money;}public void deposit(BigDecimal money) {//转出操作if (available < monrey ) {throws new InsufficientMoneyException();}abailable = available - money;}
}

充血模型(引起实体变化的因素放入实体中) ——> 贫血模型POJO(Martin Fowler 提出)MicroService ——> 贫血失忆症

public interface AccountRepository {// .....
}
public class AccountRepositoryImpl implments AccountRespository {@Autowiredprivate AccountDao accountDAO;@Autowiredprivate AccountBuilder accountBuilder; // 仓库工厂@Overridepublic Account find() {AccountDO accountDO = accountDAO.selectById(id);return accountBuilder.toAccount(accountDO);}@Overridepublic Account find(Long accountNumber) {AccountDO accountDO = accountDAO.selectByAccountNumber(AccountNumber);return accountBuilder.toAccount(accountDO);}@Overridepublic Account save(Account account) {AccountDO accountDO = accountBuilder.fromAccount(account);if (accountDO.getId() != null) {accountDAO.insert(accountDO);} else {accountDAO,update(accountDO);}return accountBuilder.toAccount(accountDO);}
}
  1. 构建防腐层 隔离外部服务(众人皆醉我独醒)
public interface BusiSafeService{// ....
}public class BusiSafeServiceImp implements public class BusiSafeServiceImp implements BusiSafeService{@Autowiredprivate RiskChkService riskChkService;public Result chekcBusi(Long userId,Long mechantAccount,BigDecimal money) {RiskCode riskCode = riskCheckService.checkPayment(...);if(“0000.equals(reskCode.getCode()){return Result.SUCCESS;	}return Result.REJECT;}}		
}
  1. 防腐层 隔离第三方组件(摆脱技术框架限制 提供无限可能)
// 值对象,只有属性,没有任何方法
public class AuditMessage {private Long userId;private Long clientAccount;private Long merchantAccount;private BigDecimal money;private Date date;....
}
public interface AuditMessageProducer{// ...
}
public class AuditMessageProducerImpl implements AuditMessageProducer {private KafkaTemplate<String,String> kafkaTemplate;public SendResult send(AuditMessage message) {String messgeBody = message.getBody();kafkaTemplate.send("some topic", messageBody);return SendResult.SUCCESS;}
}
  1. 使用领域服务, 封装跨实体业务(保持实体纯粹性,出淤泥而不染)
public interface AccountTransferService {void transfer(Account sourceAccount, Account targetAccount,Money money);	
}public class AccountTransferserviceImpl implements AccountTransferService {public void transfer(Account sourceAccount, Account targetAccount, Money money) {sourceAccount.deposit(money);targetAccount.withdraw(money);}
}

4. 最终的改造结果

public class PayServiceImpl extends PayService {private AccountRepository accountRepository;private AuditMessageProducer auditMessageProducer;private BusiSafeService busiSafeService;private AccountTranserSerivce accountTransferService;public Result pay(Account client, Account merchant, Money amount) {// 加载数据Account clientAccount = accountRepository.find(clinet.getId());Account merAccount = accountRepository.find(merchant.getId());//交易检查Result preCheck = busiSafeService.checkBusi(client,merchant,money);if(preCheck != Result.SUCCESS) {return Result.REJECT;}// 转账业务accountTransferServie.transfer(client,merchant,money);// 保存数据;accountRepository.sace(client);accountRepository.save(merchant);//发送审计AuditMessage message = new AuditMessage(client, merchant, money);auditoMessageProducer.send(message);return Result.SUCCESS;}
}

5.模型

  • 用户接口层(User Interface Layer)
  • 负责与用户交互,包括但不限于web界面、API接口、命令行界面
  • 处理用户的输入并将其转化为系统内部可处理的指令或请求
  • 展示从应用层获取的数据和信息给用户
  • 应用层(Application Layer)
  • 作为领域模型和外部世界的桥梁,它定义了应用程序的服务边界,并负责协调和编排业务逻辑。
  • 应用层包含了控制器、服务类等组件,执行业务流程,调用领域对象来完成工作,同时可能设计DTO转换。
  • 领域层 (Domain Layer)
  • 核心业务逻辑所在的地方,包含领域模型(实体、值对象、聚合根等)以及领域服务。
  • 领域层专注于表达和实现业务规则、约束和操作,它是整个架构中最关键的部分,反映的是业务领域的核心概念和知识。
  • 基础设施层(Infrastructure Layer)
  • 提供通用的技术支持和基础设施服务,如数据库访问(Repository模式)、消息队列、缓存、日志记录、安全框架等。
  • 这一层实现持久化仓储(Repository),将领域对象与数据库或其他数据存储方式解耦,确保领域层不受具体技术实现的影响。

注意几点:

  • A: 业务写在哪?

Q: 领域层,核心业务是跟随实体展开的,是不掺杂其他业务的逻辑,只关注实体的业务逻辑。

  • A: 那领域层包含什么?

Q: 实体、值对象、聚合根、领域服务

  1. 实体:具有唯一标识符和业务逻辑的对象,在领域模型中代表具有持久状态行为业务对象
  2. 值对象(Value Object): 代表不变性只读属性的业务概念,它们没有独立的身份标识,而是通过其属性的值来定义其等价性。例如地址、邮箱等。可能里面会包含校验规则。
  3. 聚合根(Aggregate Root): 在一个聚合内作为整体边界的一部分,负责维护内部一致性。它是聚合内的入口点,对外暴露方法,控制对聚合内部其他实体和值对象的访问。
  4. 领域服务(Domain Service): 当某个业务操作跨越了多个实体或者值对象,并且不自然地属于任何一个实体时,可以创建一个领域服务来封装这类业务逻辑。领域服务与实体和值对象一样,也是领域模型中的组成部分,但它更关注于处理那些不属于特定实体或值对象职责范围内的复杂业务流程。
  • A: 操作的事务是在领域层有所体现吗?

在领域驱动设计中,事务管理通常不直接在领域层体现。领域层关注的是业务逻辑的实现,而不是数据访问或持久化技术的具体细节。

  1. 事务通常是与基础层(Instructure Layer)或应用层(Application Layer)关联的概念,因为这两个层次更接近于数据库或其他数据存储系统,负责执行数据的读写操作以及相关的事务控制。
  2. 然而,在领域模型的设计过程中,我们确实需要考虑业务一致性边界和事务边界,这通常体现在聚合根的设计上。聚合根作为一组相关对象的统一入口点,它负责维护内部的一致性,并可以在一定程度上隐式地影响到事务的范围。
  3. 具体说,当一个业务操作涉及到多个实体的时候,如果这些实体都属于同一个聚合根,则他们的操作可以视为一个事务单元来处理。在这种情况下,应用层在调用领域层时,可以将整个聚合的操作包裹在一个数据库事务中,以确保数据一致性。
  4. 总结来说,虽然领域层不直接处理事务,但它通过聚合根的设计间接影响了事务边界的选择和实现。实际的事务管理代码会存在于应用层或基础设施层中。
  • A:如何判断对象之间是否是聚合关系?

部分与整体关系。比如订单聚合,订单包含客户账户、商家账户、商品列表、收货地址。
那么订单不存在了,收货地址也就没什么意义了。所以它们是聚合关系。

  • A: 聚合根的作用?

通过聚合与聚合根的设计,极大的简化整个系统内的对象关系图。

  • A: 那你说一下这个调用链呗?不知道如何写呀!!!(张了一张疑问脸)
  1. 从用户接口进来的请求
  2. 调用了应用层的服务编排类的方法(!!! 注意应用层不是之前mvc模式下的service)
    3.应用层可能会有仓库的调用、第三方服务抽象接口的调用、中间件抽象服务方法的调用(依赖倒置)
  3. 在领域层,实体中包含了具体实体的状态和实体的行为(充血模型),以及值对象(只包含属性,无标识)、聚合根(多个相关实体组成的边界)、领域服务(一些不属于某个实体的业务逻辑,但还必须是领域层的逻辑,可以定义一个领域服务来收纳配置)。
  4. 应用层对领域层进行了服务编排后,实现了模版式地调用,而不关心底层是如何是实现的。即便会出现更迭,只需要新增实现,替换实现即可,无需更改实现。
  • A: 梳理一下,这个四层架构?
  1. 基础设施层(数据库、API、缓存、网关)
  2. 领域层(聚合、(领域)实体1值对象1 (领域)实体2值对象2、领域服务)
  3. 应用层(应用服务1、应用服务2)
  4. 用户接口层(用户界面、Web服务、其他接口)
  • A 升华四层架构规范
  1. 领域层:Domain Layer: 放之四海而皆准的理想。系统的核心,纯粹表达业务能力,不需要任何外部依赖。
  2. 应用层:Application Layer: 理想与现实。协调领域对象,组织形成业务场景。只依赖于领域层
  3. 用户层:User Interface Layer:护城河,负责与用户进行交互。解释用户请求,返回用户响应、只引用应用层。
  4. 基础层:Infrastructure Layer: 业务与数据分离,为领域层提供持久化机制,为其他层提供通用技术能力。
  • 聚合与聚合根引来的问题?

一个聚合中包含聚合根和其他实体或者值对象。
那么当对其中一个实体进行统计查询的时候,这时候DDD强调了有一个聚合根作为入口,所以导致了查询的不便。
举个例子:订单聚合,订单聚合中包含订单聚合根、商品、收货地址、等。
如果说想要查询某一天某件商品的销量,那么需要首先查询出订单,在通过订单判断商品,将其累加起来。这样就造成了不必要的麻烦。真的是这样的吗?
其实,DDD推荐的是,也一直说,DDD强调的是对实体属性状态变化去产生的。而报表和查询是没必要这样做的。

  • 限界上下文

当把功能放大到各个模块的时候,就会出现领域的边界,这个边界就是限界上下文。
有了限界上下文的划分、单体、微服务、事件驱动这些架构就都只是领域之间不同的协作方式。而领域本身是保持稳定的。

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

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

相关文章

项目中使用iframe引入html 解决路由错乱问题以及父子组件传值调用方法

iframe与外部之间传值 父组件 <iframeid"iframe"src"luckysheet/index.html"frameborder"0"scrolling"no"style"width: 100%; height: 60vh; border: 0"/>const frame document.getElementById(iframe);frame.onloa…

Python综合练习之图表

文章目录 文件目录如下图标效果timeline_bar_with_graphic.htmltable_base.html articles.jsonarticlesData.pyarticlesEchartsEntity.pyarticlesEntity.py Python学习了约一个月的时间&#xff0c;这是一篇综合练习的文章。主要做的内容是通过封装对象、实现抽象方法生成统计图…

不可预测的市场中,为何有人持续胜出?

为什么经济学家和证券分析师难以预测经济或股价走势&#xff0c;而少数投资大师却能几十年持续复利&#xff1f;这两个问题看似矛盾&#xff0c;既然无法预测&#xff0c;为何又能产生确定性的赚钱结果呢&#xff1f; 有人认为这是因为幸存者偏差。然而&#xff0c;三十年以上连…

优优嗨聚集团:债务逾期,如何应对与解决?

在现代社会&#xff0c;债务问题已成为越来越多人面临的难题。债务逾期不仅会给个人带来巨大的经济压力&#xff0c;还会影响个人信用记录&#xff0c;甚至可能引发法律纠纷。那么&#xff0c;当债务逾期时&#xff0c;我们应该如何应对与解决呢&#xff1f; 一、了解债务情况 …

14.STL 常用算法

14、STL常用算法 概述&#xff1a; 算法主要是由头文件 、、 组成 是所有STL头文件中最大的一个&#xff0c;范围涉及到比较、 交换、查找、遍历操作、复制、修改等等 体积很小&#xff0c;只包括几个在序列上面进行简单数学运算的模板函数 定义了一些模板类,用以声明函数对象…

1.3 面试经典150题 - 删除有序数组中的重复项

删除有序数组中的重复项 class Solution:def removeDuplicates(self, nums: List[int]) -> int:# 处理边界数据if not nums: return 0if len(nums) 1: return 1# 两个指针&#xff0c;一个记录当前有多少个不重复值的个数&#xff0c;一个记录最新遍历到的值count 1tmp …

C# ObjectArx 绘制表格并设置单元格合并

第一行默认是标题&#xff0c;可设置行【RowType】进行设置类型 Document doc Application.DocumentManager.MdiActiveDocument;using (Transaction tr doc.TransactionManager.StartOpenCloseTransaction()){BlockTable bt tr.GetObject(doc.Database.BlockTableId, OpenMo…

GZ075 云计算应用赛题第9套

2023年全国职业院校技能大赛&#xff08;高职组&#xff09; “云计算应用”赛项赛卷9 某企业根据自身业务需求&#xff0c;实施数字化转型&#xff0c;规划和建设数字化平台&#xff0c;平台聚焦“DevOps开发运维一体化”和“数据驱动产品开发”&#xff0c;拟采用开源OpenSt…

Python3 中常用字符串函数介绍

介绍 Python 中有几个与 字符串数据类型相关的内置函数。这些函数让我们能够轻松修改和操作字符串。我们可以将函数视为在代码元素上执行的操作。内置函数是在 Python 编程语言中定义的&#xff0c;并且可以随时供我们使用的函数。 在本教程中&#xff0c;我们将介绍在 Pytho…

导轨式信号隔离变送器比例阀门线性驱动器4-20mA/0-5V/0-10V转0-165mA/0-80mA/0-1A/0-2A/0-4A

主要特性 精度、线性度误差等级&#xff1a; 0.1、0.2、0.5 级4-20mA/0-5V/0-10V 等标准信号输入0~100mA/0~500mA/0~1A/0-5A 等电流信号输出0~1V(max 2A)/0~10V/0-24V(max 5A) 等电压信号输出信号输入/信号输出 3000VDC 隔离辅助电源&#xff1a;12V、15V 或 24V 直流单电源供…

【微服务】日志搜集elasticsearch+kibana+filebeat(单机)

日志搜集eskibanafilebeat&#xff08;单机&#xff09; 日志直接输出到es中&#xff0c;适用于日志量小的项目 基于7.17.16版本 主要配置在于filebeat&#xff0c; es kibana配置改动不大 环境部署 es kibana单机环境部署 略 解压即可 常见报错&#xff0c;百度即可。 记录…

Android 和 IOS 设备唯一ID如何选择

我们在做Android/IOS应用或游戏的时候,或许总会碰到要获取设备唯一id来标识或跟踪玩家。但随着系统安全性的提高,加强用户的隐私安全,获取设备唯一ID变得越来越困难了,下面我们来分析一下,看看哪些还可以满足我们需求,同时,如果您有关于获取设备唯一ID的新发现,欢迎留言…

【Vue监听属性详细介绍】

Vue监听属性详细介绍 1. 监听属性2. watch 属性3. 计算属性&#xff08;Computed Properties&#xff09;4. 侦听器&#xff08;Listeners&#xff09;方法5. .sync 修饰符6. 注意事项 1. 监听属性 在Vue中&#xff0c;监听属性是一个十分重要的特性&#xff0c;它允许你监听和…

揭秘铭文技术: 它如何改变你的数字世界?

在数字世界的演变过程中&#xff0c;区块链技术被广泛认为是一种革命性的创新&#xff0c;为众多行业和领域带来深远的影响。然而&#xff0c;区块链的潜力远不止于此。近年来&#xff0c;一种新兴应用——区块链铭文&#xff0c;正在逐渐引起人们的关注&#xff0c;成为数字世…

修改csdn的字体大小颜色

修改csdn的字体大小颜色 修改csdn的字体大小颜色 修改csdn的字体大小颜色一、设置字体与颜色格式二、修改字体格式三、修改字体颜色 一、设置字体与颜色格式 <font face"华文行楷" colorred size5>本字体是华文行楷&#xff0c;红色&#xff0c;5号大小</fo…

怎样获取power shell 的全部可用命令?2/5(篇幅有点长,分成5份)

在power shell 窗口中&#xff0c;有一个获取全部可用命令的命令&#xff1a;get-command&#xff0c;获取到的命令有1640多个&#xff0c;够学习了吧&#xff1f;那么&#xff0c;power shell 命令有哪些类别呢&#xff1f; PowerShell命令可以分为以下几类&#xff1a; Cmdl…

TS学习笔记二:基础类型及变量声明

本节介绍TypeScript中的基础类型及变量声明方式的说明。TypeScript支持与JavaScript几乎相同的数据类型&#xff0c;此外还提供了实用的枚举类型方便我们使用。基础类型包括&#xff1a;数字&#xff0c;字符串&#xff0c;结构体&#xff0c;布尔值等。 学习视频 TS学习笔记二…

java发送邮件(注:本章以163邮箱为例)

目录 前言 一邮件服务器与传输协议 二.发送邮件思路 2.1注册163邮箱: 2.2、打开邮箱服务获取授权码 三.代码实现邮件发送 3.1第三方jar包 3.2创建邮件工具类 3.3编写测试类 前言 电子邮件的应用非常广泛&#xff0c;例如在某网站注册了一个账户&#xff0c;自动发送一…

机器学习在什么场景下最常用-九五小庞

机器学习在多个场景中都有广泛的应用&#xff0c;下面是一些常见的应用场景&#xff1a; 自然语言处理&#xff08;NLP&#xff09;&#xff1a;如语音识别、自动翻译、情感分析、垃圾邮件过滤等。数据挖掘和分析&#xff1a;如市场分析、用户画像、推荐系统、欺诈检测等。智能…

你不得不知道的常用 Git 命令

最近在学习的时候发现 git 命令没有自己想象中那么简单&#xff0c;特此做一期 《 常用 Git 命令 》&#xff0c;不仅是给掘友分享&#xff0c;也能巩固自己学到的知识。 在此向大家推荐一个学习 git 指令的小游戏 Learn Git Branching&#xff0c;以通关的方式进行学习&#…