领域驱动:贫血模型和充血模型

2023-10-08 21:59

本文主要是介绍领域驱动:贫血模型和充血模型,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

什么是领域驱动

领域模型是通过识别领域对象与行为来连接现实主体与操作之间的映射关系。对象行为的组织原则更体现面向对象对象设计思想,通过聚合,解耦抽象等方式达到系统的可复用,可维护,可扩展能力。

MVC

MVC 三层架构中 M 表示 model ,V 表示的是 View, C 表示的是 Controller, 也就是分成了三层: 数据层, 表示层,逻辑层。

  1. 模型: 负责存储系统的中心数据
  2. 视图:将数据显示给用户
  3. 控制器: 处理用户输入的信息,负责读取视图数据,控制用户输入,并向模型写入数据。

后端项目一般是分成三层: Repository 层,Service 层,Controller 层,其中,Repository 负责数据访问,Service 负责处理业务逻辑, Controller 负责暴露接口。

什么是贫血模型

贫血模型领域对象很简单,只有所有属性的 get/set 方式,与少量的属性值转换,不包含任何业务逻辑, 不关心数据对象的持久化,只用来做数据对象的承载和传递介质。

领域对象

@Entity
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class User {@Idprivate String userId;private String userName;private String password;private boolean isLock;
}

真正的业务逻辑在领域服务中负责实现,此服务中引入持久化仓库, 在业务逻辑之后持久化到仓库中,并可发布领域事件。

Service 层, 领域服务, 业务处理,使用领域对象进行数据承载。

public interface UserService {void create(User user);void edit(User user);void changePassword(String userId, String newPassword);void lock(String userId);void unlock(String userId);}@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserRepository repo;@Overridepublic void edit(User user) {User dbUser = repo.findById(user.getUserId()).get();dbUser.setUserName(user.getUserName());repo.save(dbUser);// 发布领域事件 ...}@Overridepublic void lock(String userId) {User dbUser = repo.findById(userId).get();dbUser.setLock(true);repo.save(dbUser);// 发布领域事件 ...}// ... 省略完整代码
}

再看个贫血模型的具体例子:

// Controller+VO(View Object) //
public class UserController {private UserService userService; //通过构造函数或者IOC框架注入public UserVo getUserById(Long userId) {UserBo userBo = userService.getUserById(userId);UserVo userVo = [...convert userBo to userVo...];return userVo;}
}public class UserVo {//省略其他属性、get/set/construct方法private Long id;private String name;private String cellphone;
}// Service+BO(Business Object) //
public class UserService {private UserRepository userRepository; //通过构造函数或者IOC框架注入public UserBo getUserById(Long userId) {UserEntity userEntity = userRepository.getUserById(userId);UserBo userBo = [...convert userEntity to userBo...];return userBo;}
}public class UserBo {//省略其他属性、get/set/construct方法private Long id;private String name;private String cellphone;
}// Repository+Entity //
public class UserRepository {public UserEntity getUserById(Long userId) { //... }
}public class UserEntity {//省略其他属性、get/set/construct方法private Long id;private String name;private String cellphone;
}

UserEntity 和 UserRepository 负责数据访问, UserBo 和 UserService 负责处理业务逻辑, UserVo 和 UserController 属于接口层。

这样 UserBo 中只包含属性数据,不包含业务逻辑的累,叫做贫血模式

传统的贫血模型其实很受欢迎, 贫血模型是面向过程的编程风格。

  • 开发系统业务比较简单,只要实现 CRUD 操作即可, 不需要费力设计充血模型, 其次贫血模型足够应对这种简单的业务操作。
  • 充血模型的设计比贫血模型更加有难度,充血模型是面向对象的编程风格,一开始就要想好,对数据要暴露哪些操作,定义哪些业务逻辑, 而不是和贫血模型一样,只要设计好模型,后续有什么功能需求,Service 就定义什么操作。
  • 思维固化,转型有成本,基于贫血模型开发多年,一下要转换成充血模型,领域驱动,有一定的学习成本。

充血模型

充血模型包含领域对象作用此对象的相关行为, 领域对象不仅好汉属性,还包含业务处理逻辑,同时也包含对象的持久化操作。

@Entity
@Data
@Builder
@AllArgsConstructor
public class User implements UserService {@Idprivate String userId;private String userName;private String password;private boolean isLock;// 持久化仓库@Transientprivate UserRepository repo;// 是否是持久化对象@Transientprivate boolean isRepository;@PostLoadpublic void per() {isRepository = true;}public User() {}public User(UserRepository repo) {this.repo = repo;}@Overridepublic void create(User user) {repo.save(user);}@Overridepublic void edit(User user) {if (!isRepository) {throw new RuntimeException("用户不存在");}userName = user.userName;repo.save(this);// 发布领域事件 ...}@Overridepublic void lock() {if (!isRepository) {throw new RuntimeException("用户不存在");}isLock = true;repo.save(this);// 发布领域事件 ...}}

领域模型的优点

  • 对象自治度很高,表达能力很强,非常适合复杂的业务逻辑的实现,可靠复用程度比较高。更符合面向对象的思想。
  • 当前充血模型不够存粹,将业务逻辑和持久化操作放在一块,有一定的耦合度。

在领域对象行为比较复杂的情况下, 需要多个行为共享对象状态时,充血模型表现更强。

充血模型2

上面的充血模型,不仅包含业务逻辑,还包含数据持久化,为解决业务逻辑不存粹的问题,可以将持久化操作移出去。

@Entity
@Data
@Builder
@AllArgsConstructor
public class User implements UserService {@Idprivate String userId;private String userName;private String password;private boolean isLock;// 是否是持久化对象@Transientprivate boolean isRepository;@Overridepublic void create(User user) {user.userId = UUID.randomUUID().toString();}@Overridepublic void edit(User user) {userName = user.userName;}@Overridepublic void lock() {isLock = true;}}@Service
public class UserManager {@Autowiredprivate UserRepository repo;public User findOne(String userId){return repo.findById(userId).get();}public void edit(User u) {User user = findOne(u.getUserId());user.edit(u);repo.save(user);// 发布领域事件 ...}public void lock(String userId) {User user = findOne(userId);user.lock();repo.save(user);// 发布领域事件 ...}
}
  • 去掉了持久化的入侵,业务更加存粹

什么场景选择充血模型

基于充血模型的 DDD 开发模式,更适合复杂的系统开发,比如包含各种利息计算模型,还款模型的复杂业务的金融系统。

领域驱动设计主要是用来指导如何解偶业务系统,划分业务模块, 定义业务领域模型及其交互。他的发展主要是由于微服务,微服务不仅仅要关注服务治理,监控,调用链追踪, API 网关等问题,还有个重要的问题,就是对公司业务进行拆分,形成微服务。对领域驱动设计关键在于对业务的熟悉理解程度,领域驱动设计的思想是: 轻 Service ,重 Domain。

我们平时开发时,大部分是 SQL 驱动,接到一个后端开发需求时,首先是去看接口如何对应到数据库中,要访问哪些表,哪些库,然后思考 SQL 如何写。这样会看到,类似的SQL 到处都是,通常为一个 需求写一个 SQL。

对于领域驱动,我们首先需要理清所有业务,包括定义模型包含的属性和方法,领域模型相当于可复用业务的中间层,新的需求需要基于之前定义好的业务来完成。

欢迎关注公众号:程序员开发者社区

在这里插入图片描述

参考资料
  • https://zhuanlan.zhihu.com/p/147879821
  • https://juejin.cn/post/6856635975666401288

这篇关于领域驱动:贫血模型和充血模型的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/168263

相关文章

Python基于火山引擎豆包大模型搭建QQ机器人详细教程(2024年最新)

《Python基于火山引擎豆包大模型搭建QQ机器人详细教程(2024年最新)》:本文主要介绍Python基于火山引擎豆包大模型搭建QQ机器人详细的相关资料,包括开通模型、配置APIKEY鉴权和SD... 目录豆包大模型概述开通模型付费安装 SDK 环境配置 API KEY 鉴权Ark 模型接口Prompt

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI(简称 RVC)模型是一个基于 VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的简单易用的语音转换框架。 具有以下特点 简单易用:RVC 模型通过简单易用的网页界面,使得用户无需深入了

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

图神经网络模型介绍(1)

我们将图神经网络分为基于谱域的模型和基于空域的模型,并按照发展顺序详解每个类别中的重要模型。 1.1基于谱域的图神经网络         谱域上的图卷积在图学习迈向深度学习的发展历程中起到了关键的作用。本节主要介绍三个具有代表性的谱域图神经网络:谱图卷积网络、切比雪夫网络和图卷积网络。 (1)谱图卷积网络 卷积定理:函数卷积的傅里叶变换是函数傅里叶变换的乘积,即F{f*g}

秋招最新大模型算法面试,熬夜都要肝完它

💥大家在面试大模型LLM这个板块的时候,不知道面试完会不会复盘、总结,做笔记的习惯,这份大模型算法岗面试八股笔记也帮助不少人拿到过offer ✨对于面试大模型算法工程师会有一定的帮助,都附有完整答案,熬夜也要看完,祝大家一臂之力 这份《大模型算法工程师面试题》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

AI Toolkit + H100 GPU,一小时内微调最新热门文生图模型 FLUX

上个月,FLUX 席卷了互联网,这并非没有原因。他们声称优于 DALLE 3、Ideogram 和 Stable Diffusion 3 等模型,而这一点已被证明是有依据的。随着越来越多的流行图像生成工具(如 Stable Diffusion Web UI Forge 和 ComyUI)开始支持这些模型,FLUX 在 Stable Diffusion 领域的扩展将会持续下去。 自 FLU