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

这篇具有很好参考价值的文章主要介绍了【架构师成长之领域驱动开发】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

项目中的“坏”味道

  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 {
	@Autowired
	private AccountDao accountDAO;
	@Autowired
	private AccountBuilder accountBuilder; // 仓库工厂

	@Override
	public Account find() {
		AccountDO accountDO = accountDAO.selectById(id);
		return accountBuilder.toAccount(accountDO);
	}
	@Override
	public Account find(Long accountNumber) {
		AccountDO accountDO = accountDAO.selectByAccountNumber(AccountNumber);
		return accountBuilder.toAccount(accountDO);
	}

	@Override
	public 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{
   @Autowired
   private 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强调的是对实体属性状态变化去产生的。而报表和查询是没必要这样做的。

  • 限界上下文

当把功能放大到各个模块的时候,就会出现领域的边界,这个边界就是限界上下文。
有了限界上下文的划分、单体、微服务、事件驱动这些架构就都只是领域之间不同的协作方式。而领域本身是保持稳定的。文章来源地址https://www.toymoban.com/news/detail-790136.html

到了这里,关于【架构师成长之领域驱动开发】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 快速理解DDD领域驱动设计架构思想-基础篇

    本文与大家一起学习并介绍领域驱动设计(Domain Drive Design) 简称DDD,以及为什么我们需要领域驱动设计,它有哪些优缺点,尽量用一些通俗易懂文字来描述讲解领域驱动设计,本篇并不会从深层大论述讲解落地实现,这些大家可以在了解入门后再去深层次学习探讨或在后续进阶

    2024年02月10日
    浏览(12)
  • 快速理解DDD领域驱动设计架构思想-基础篇 | 京东物流技术团队

    快速理解DDD领域驱动设计架构思想-基础篇 | 京东物流技术团队

    本文与大家一起学习并介绍领域驱动设计(Domain Drive Design) 简称DDD,以及为什么我们需要领域驱动设计,它有哪些优缺点,尽量用一些通俗易懂文字来描述讲解领域驱动设计,本篇并不会从深层大论述讲解落地实现,这些大家可以在了解入门后再去深层次学习探讨或在后续进阶

    2024年02月09日
    浏览(12)
  • 软件架构演进过程与微服务设计中的领域驱动设计(DDD)

    软件架构的演进是一个不断改进和解决问题的过程。从传统架构到面向服务架构(SOA),再到微服务架构,每个阶段都带来了新的技术和解决方案。而在微服务架构中,领域驱动设计(DDD)起着至关重要的作用,它能够提高系统的可扩展性、可维护性和可理解性。本文将介绍软件架

    2024年02月16日
    浏览(9)
  • 低代码信创开发核心技术(三):MDA模型驱动架构及元数据系统设计

    写最后一篇文章的时候,我本人其实犹豫了半年,在想是否发布出这篇文章,因为可能会动了很多人的利益。所以这篇文章既是整个低代码信创开发的高度总结,也是最为精华的一部分,它点明了低代码中最为核心的技术。虽然你在读这篇文章的时候会有犹抱琵琶半遮面的感

    2024年02月04日
    浏览(17)
  • 领域驱动设计&事件驱动框架&命令查询责任分离&测试驱动开发

    领域驱动设计&事件驱动框架&命令查询责任分离&测试驱动开发

    领域驱动设计: DDD 事件驱动框架: Event Driven Architecture 命令查询责任分离: CQRS(Command Query Responsibility Segregation) 测试驱动开发: TDD 入口是系统外部客户访问系统内部的端口。常见的入口如http, rpc, 命令行,外部消息(消费kafka,rocketmq或者zk, etcd的通知消息)。 入口的职责:解析外部

    2024年02月04日
    浏览(10)
  • 史上最全最详细的Java架构师成长路径图,程序员必备

    史上最全最详细的Java架构师成长路径图,程序员必备

    从新手码农到高级架构师,要经过几步?要多努力,才能成为为人倚重的技术专家?本文将为你带来一张程序员发展路径图,但你需要知道的是,天下没有普适的道理,具体问题还需具体分析,实践才能出真知。 架构师的“内功” 我认为,架构师的内功主要包含三部分: 判

    2024年02月01日
    浏览(15)
  • 为什么阿里人能够快速成长?看完他们 Java 架构进化笔记,我秒懂!

    为什么阿里人能够快速成长?看完他们 Java 架构进化笔记,我秒懂!

    0-1 年入门: Java 基础复盘 (面向对象+Java 的超类+Java 的反射机制+异常处理+集合+泛型+基础 IO 操作+多线程+网络编程+JDK 新特性) Web 编程初探 (Servlet+MySQL 数据库+商品管理系统实战) SSM 从入门到精通 (Spring+SpringMVC+Mybatis+商品管理系统实战-SSM 版) SpringBoot 快速上手 (Spr

    2023年04月19日
    浏览(14)
  • DDD进阶_领域事件是什么?如何开展领域事件驱动开发工作?

    DDD进阶_领域事件是什么?如何开展领域事件驱动开发工作?

    DDD从入门到精通,系列文章传送地址,请点击本链接。   目录 一、什么是领域事件 二、如何识别领域事件 三、领域事件的数据一致性 四、领域事件分类 1、微服务内的领域事件 2、微服务之间的领域事件 五、领域事件案例 六、领域事件总体架构图 1. 事件构建和发布 2、事

    2024年02月15日
    浏览(9)
  • ubuntu-server部署hive-part3-安装mysql,最新大数据开发架构师成长路线

    ubuntu-server部署hive-part3-安装mysql,最新大数据开发架构师成长路线

    不再报类似上方的错误,以mysql用户执行mysql命令,报错如下,说明可以继续安装。 初始化 以mysql用户执行如下命令: mysqld --user=mysql --basedir=/usr/local/mysql/ --datadir=/usr/local/mysql/data --initialize 说明: –user:以操作系统mysql用户的身份初始化数据库,产生文件mysql是拥有者 –ba

    2024年04月15日
    浏览(15)
  • 告别过去,拥抱未来:一个Java开发者的成长之路

    时光飞逝,不知不觉已经到了大四毕业的时候。回顾这四年的学生生涯,Java开发是让我最为热爱和投入的一部分。在这里,我想和大家分享我在Java开发方面的收获、经验和感悟,同时也向过去的自己告别,迎接未来的挑战。 在大一的时候,我们学习了Java编程基础,当时我并

    2024年02月08日
    浏览(12)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包