新闻详情

新闻详情

首页 / 资讯中心 / 详情

业务逻辑全塞在 Service 层,项目上线半年后为什么连加个字段都不敢?

发布时间:2026/9/29 21:43:23来源:尧图网络
业务逻辑全塞在 Service 层,项目上线半年后为什么连加个字段都不敢?
业务逻辑全塞在 Service 层项目上线半年后为什么连加个字段都不敢你在面试时肯定听过“高内聚低耦合”。但看看实际的项目代码大部分情况还是从 Controller 接收 DTO传给 ServiceService 里写几百行甚至几千行的if-else和业务逻辑最后调用 Dao 存进数据库。这套 CRUD 模式在项目初期开发极快这也是它能流行这么多年的原因。但等项目上线半年后业务开始加需求了。比如原来只卖普通商品现在要加虚拟商品、组合商品、秒杀商品。原来只用校验库存现在还要算会员折扣、积分抵扣、黑名单拦截。这个时候你的OrderService.createOrder()方法可能已经膨胀到了 800 行。当你接到一个“商品下架时判断如果是组合商品则同时下架子商品”的需求时你打开 Service 层看着里面错综复杂的校验和状态流转心里只剩下一个想法加个字段或者改个if会不会把别的逻辑搞崩这就是典型的发展痛点代码腐化。不敢重构的原因是没有边界。这种把所有状态判断、计算逻辑都堆在 Service 层而实体类Entity只包含get和set方法的写法被称为“贫血模型”Anemic Domain Model。数据和行为是彻底分离的。领域驱动设计DDDDomain-Driven Design给出了一种解法。核心变化是把业务规则收拢回对象本身也就是所谓的“充血模型”。来看一个直观的例子。在传统的贫血模型中我们修改密码通常是这样写的publicvoidchangePassword(LonguserId,StringnewPassword){UseruseruserMapper.selectById(userId);if(user.getStatus()UserStatus.LOCKED){thrownewBizException(账号已锁定);}// 很多很多其他校验...user.setPassword(passwordEncoder.encode(newPassword));userMapper.update(user);}这段代码看起来没问题但User的状态规则散落在各个 Service 里。如果哪天加了一个新状态“待激活”你需要去所有用到 User 的 Service 里把相关判断都加一遍。漏掉一个就是线上 Bug。换成 DDD 的充血模型思路业务逻辑是属于User领域的它应该长这样// User 实体内部publicvoidchangePassword(StringnewPassword,PasswordEncoderencoder){if(this.statusUserStatus.LOCKED){thrownewBizException(账号已锁定无法修改密码);}this.passwordencoder.encode(newPassword);}然后在应用服务层Application Service里代码变成了纯粹的流程编排publicvoidchangePassword(LonguserId,StringnewPassword){UseruseruserRepository.findById(userId);user.changePassword(newPassword,passwordEncoder);userRepository.save(user);}注意到了吗核心业务规则不再由 Service 掌管而是实体类自己维护自己的不变量Invariants。不管有多少个入口需要修改密码校验逻辑永远在实体内部不会散落。这只是 DDD 的冰山一角。更宏观层面上DDD 强调“限界上下文”Bounded Context。在大型系统中用户的概念在登录模块、订单模块、物流模块里是完全不同的。如果不做上下文隔离大家都去修改那张包含了上百个字段的巨大t_user表项目最终必然变成一团乱麻。划清边界让领域对象自己管理自己的状态是 DDD 应对软件复杂度的有效手段。但千万别为了 DDD 而 DDD。如果你只是在写一个简单的后台管理系统每天的需求就是加减几个表单字段用 MVC 加上贫血模型绝对是开发效率最高的。DDD 引入了聚合根、值对象、领域服务等大量新概念它的存在是为了应对复杂的业务变化而不是为了让简单的增删改查变得高端。评估你的项目如果是强业务规则、多状态流转、高复杂度的系统下一次写代码前可以试着先把逻辑放进对象里而不是 Service 里。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

函数的使用规则: 2026/9/29 22:42:14

函数的使用规则:

# 函数可以实现一个特定的功能 # print() 控制台打印输出 # input() 获取键盘的输入 # type() 获取变量的类型 # len() 容器的长度 # 我们自己如何定义一个函数,实现特定的功能 # 函数: 将多行代码(实现一个特定的功能)写在一块,起个名字,在需要的时候进行调用 # 函数的…

阅读更多 →
正点原子RK3588开发板资料获取与SDK编译烧录全攻略 2026/9/29 22:42:14

正点原子RK3588开发板资料获取与SDK编译烧录全攻略

1. 拿到RK3588开发板之后,资料到底该从哪里下手刚拿到正点原子RK3588开发板那会儿,我第一反应不是急着上电,而是先把资料体系摸清楚。这块板子跟早年玩STM32那种“一个压缩包走天下”的节奏完全不一样,RK3588属于典型的高性能异构…

阅读更多 →
Win10开机转圈慢启动?5种系统自带修复方法详解 2026/9/29 22:42:14

Win10开机转圈慢启动?5种系统自带修复方法详解

开机转圈这事儿,估计每个用过Win10的人都遇到过。好一点的情况是转个几十秒能进桌面,严重点的能转三分钟往上,屏幕中间那个圆点转得人心里发毛。更烦人的是,明明看着转圈,却怎么也进不去桌面,鼠标能晃&…

阅读更多 →
RTX 50系笔记本功耗解锁:NvpwrControl实操与风险控制 2026/9/29 22:42:14

RTX 50系笔记本功耗解锁:NvpwrControl实操与风险控制

1. 从一条热搜说起:50系笔记本的功耗墙到底被动了什么最近数码圈里最热闹的话题之一,就是围绕英伟达RTX 50系笔记本显卡的功耗限制讨论。不少玩家发现,原本被厂商锁死的功耗上限,似乎有了被重新调整的空间,于是“大ROO…

阅读更多 →
OpenStack私有云搭建实战:Kolla-Ansible部署与虚拟机创建 2026/9/29 22:42:14

OpenStack私有云搭建实战:Kolla-Ansible部署与虚拟机创建

简介:这份文档面向云计算初学者与运维人员,系统讲解如何从零搭建一套 OpenStack 私有云平台,解决环境准备、组件安装与网络配置等实操问题。资源包共 1 个 doc 文件,约 119KB,以图文步骤形式组织内容,便于按…

阅读更多 →
SQLiteCursor.getCount() 首次调用为何要锁定数据库?一次讲透 2026/9/29 22:42:07

SQLiteCursor.getCount() 首次调用为何要锁定数据库?一次讲透

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉