如何优雅的进行业务分层
1.什么是应用分层
说起应用分层,大部分人都会认为这个不是很简单嘛 就controller,service, mapper三层。
看起来简单,很多人其实并没有把他们职责划分开,在很多代码中,controller做的逻辑比service还多,service往往当成透传了,这其实是很多人开发代码都没有注意到的地方,反正功能也能用,至于放哪无所谓呗。
这样往往造成后面代码无法复用,层级关系混乱,对后续代码的维护非常麻烦。的确在这些人眼中分层只是一个形式,前辈们的代码这么写的,其他项目代码这么写的,那么我也这么跟着写。但是在真正的团队开发中每个人的习惯都不同,写出来的代码必然带着自己的标签,有的人习惯controller写大量的业务逻辑,有的人习惯在service中之间调用远程服务,这样就导致了每个人的开发代码风格完全不同,后续其他人修改的时候,一看,我靠这个人写的代码和我平常的习惯完全不同,修改的时候到底是按着自己以前的习惯改,还是跟着前辈们走,这又是个艰难的选择,选择一旦有偏差,你的后辈又维护你的代码的时候,恐怕就要骂人了。所以一个好的应用分层需要具备以下几点:
- 方便后续代码进行维护扩展;
- 分层的效果需要让整个团队都接受;
- 各个层职责边界清晰。
2、如何进行分层
2.1、阿里规范
在阿里的编码规范中约束的分层如下:
开放接口层:可直接封装 Service 方法暴露成 RPC 接口;通过 Web 封装成 http 接口;进行 网关安全控制、流量控制等。
终端显示层:各个端的模板渲染并执行显示的层。当前主要是 velocity 渲染,JS 渲染, JSP 渲染,移动端展示等。
Web 层:主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等。
Service 层:相对具体的业务逻辑服务层。
Manager 层:通用业务处理层,
它有如下特征:
- 对第三方平台封装的层,预处理返回结果及转化异常信息;
- 对Service层通用能力的下沉,如缓存方案、中间件通用处理;
- 与DAO层交互,对多个DAO的组合复用。
DAO 层:数据访问层,与底层 MySQL、Oracle、Hbase 进行数据交互。
阿里巴巴规约中的分层比较清晰简单明了,但是描述得还是过于简单了,以及service层和manager层有很多同学还是有点分不清楚之间的关系,就导致了很多项目中根本没有Manager层的存在。下面介绍一下具体业务中应该如何实现分层。
2.2、优化分层
从我们的业务开发中总结了一个较为的理想模型,这里要先说明一下由于我们的rpc框架选用的是thrift可能会比其他的一些rpc框架例如dubbo会多出一层,作用和controller层类似:
最上层controller和TService是阿里分层规范里面的第一层:轻业务逻辑,参数校验,异常兜底。通常这种接口可以轻易更换接口类型,所以业务逻辑必须要轻,甚至不做具体逻辑。
Service:业务层,复用性较低,这里推荐每一个controller方法都得对应一个service,不要把业务编排放在controller中去做,为什么呢?如果我们把业务编排放在controller层去做的话,如果以后我们要接入thrift,我们这里又需要把业务编排在做一次,这样会导致我们每接入一个入口层这个代码都得重新复制一份如下图所示:
这样大量的重复工作必定会导致我们开发效率下降,所以我们需要把业务编排逻辑都得放进service中去做:
Mannager:可复用逻辑层。这里的Mannager可以是单个服务的,比如我们的cache,mq等等,当然也可以是复合的,当你需要调用多个Mannager的时候,这个可以合为一个Mannager,比如逻辑上的连表查询等。如果是httpMannager或rpcMannager需要在这一层做一些数据转换
DAO:数据库访问层。主要负责“操作数据库的某张表,映射到某个java对象”,dao应该只允许自己的Service访问,其他Service要访问我的数据必须通过对应的Service。
3、分层领域模型的转换
在阿里巴巴编码规约中列举了下面几个领域模型规约:
- DO(Data Object):与数据库表结构一一对应,通过DAO层向上传输数据源对象。
- DTO(Data Transfer Object):数据传输对象,Service或Manager向外传输的对象。
- BO(Business Object):业务对象。由Service层输出的封装业务逻辑的对象。
- AO(Application Object):应用对象。在Web层与Service层之间抽象的复用对象模型,极为贴近展示层,复用度不高。
- VO(View Object):显示层对象,通常是Web向模板渲染引擎层传输的对象。
- Query:数据查询对象,各层接收上层的查询请求。注意超过2个参数的查询封装,禁止使用Map类来传输。
每一个层基本都自己对应的领域模型,这样就导致了有些人过于追求每一层都是用自己的领域模型,这样就导致了一个对象可能会出现3次甚至4次转换在一次请求中,当返回的时候同样也会出现3-4次转换,这样有可能一次完整的请求-返回会出现很多次对象转换。如果在开发中真的按照这么来,恐怕就别写其他的了,一天就光写这个重复无用的逻辑算了吧。
所以我们得采取一个折中的方案:1、允许Service/Manager可以操作数据领域模型,对于这个层级来说,本来自己做的工作也是做的是业务逻辑处理和数据组装。2、Controller/TService层的领域模型不允许传入DAO层,这样就不符合职责划分了。3、同理,不允许DAO层的数据传入到Controller/TService。
4、总结
总的来说业务分层对于代码规范是比较重要,决定着以后的代码是否可复用,是否职责清晰,边界清晰。
当然这种分层其实见仁见智, 团队中的所有人的分层习惯也不同,所以很难权衡出一个标准的准则,总的来说只要满足职责逻辑清晰,后续维护容易,就是好的分层。
相关文章:

如何优雅的进行业务分层
1.什么是应用分层 说起应用分层,大部分人都会认为这个不是很简单嘛 就controller,service, mapper三层。 看起来简单,很多人其实并没有把他们职责划分开,在很多代码中,controller做的逻辑比service还多,service往往当…...
C++的std命名空间
总以为自己懂了,可是仔细想想,多问自己几个问题,发现好像又不是很清楚 命名空间(Namespace)是C中一种用于解决命名冲突问题的机制,它能够将全局作用域划分为若干个不同的区域,每个区域内可以有…...

unity学习笔记
一、射线检测 如何让鼠标点击某个位置,游戏角色就能移动到该位置? 实现的原理分析:我们能看见游戏的东西就是摄像机拍摄到的东西,所以摄像机的镜平面就是当前能看到的了。 那接下来我们可以让摄像机发射一条射线,鼠标…...

使用SpringBoot和ZXing实现二维码生成与解析
一、ZXing简介 ZXing是一个开源的,用Java实现的多种格式的1D/2D条码图像处理库。它包含了用于解析多种格式的1D/2D条形码的工具类,目标是能够对QR编码,Data Matrix, UPC的1D条形码进行解码。在二维码编制上,ZXing巧妙地利用构成计…...

C++模板—函数模板、类模板
目录 一、函数模板 1、概念 2、格式 3、实例化 4、模板参数的匹配 二、类模板 1、定义格式 2、实例化 交换两个变量的值,针对不同类型,我们可以使用函数重载实现。 void Swap(double& left, double& right) {double tmp left;left ri…...

Monkey
一、Monkey的概念 “猴子测试”是指没有测试经验的人甚至对计算机根本不了解的人(就像猴子一样)不需要知道程序的任何用户交互方面的知识,如果给他一个程序,他就会针对他看到的界面进行操作,其操作是无目的的、乱点乱按…...

SQL中left join、right join、inner join等的区别
一张图可以简洁明了的理解出left join、right join、join、inner join的区别: 1、left join 就是“左连接”,表1左连接表2,以左为主,表示以表1为主,关联上表2的数据,查出来的结果显示左边的所有数据&#…...

算法学习—排序
排序算法 一、选择排序 1.算法简介 选择排序是一个简单直观的排序方法,它的工作原理很简单,首先从未排序序列中找到最大的元素,放到已排序序列的末尾,重复上述步骤,直到所有元素排序完毕。 2.算法描述 1ÿ…...

在Pycharm中创建项目新环境,安装Pytorch
在python项目中,很多项目使用的各类包的版本是不一致的。所以我们可以对每个项目有专属于它的环境。所以这个文章就是教你如何创建新环境。 一、创建新环境 首先我们需要去官网下载conda。然后在Pycharm下面添加conda的可执行文件。 用conda创建新环境。 二、…...
linux里source、sh、bash、./有什么区别
1、source source a.sh 在当前shell内去读取、执行a.sh,而a.sh不需要有"执行权限" source命令可以简写为"." . a.sh 注意:中间是有空格的。 2、sh/bash sh a.sh bash a.sh 都是打开一个subshell去读取、执行a.sh,而a.…...

IDEA编译器技巧-提示词忽略大小写
IDEA编译器技巧-提示词忽略大小写 写代码时,每次创建对象都要按住 Shift 字母 做大写开头, 废手, 下面通过编译器配置解放Shift 键 setting -> Editor -> General -> Code Completion -> Match case 把这个√去掉, 创建对象就不需要再按住 Shift 键 示例: 1.…...

【MySQL】MySQL安装 环境初始化
MySQL安装 MYSQL官网 安装完成后,傻瓜下一步即可 配置一下环境变量即可 (1) 初始化MySQL, 管理员身份运行 mysqld --initialize-insecure(2) 注册 mysqld mysqld -install# 如果记录以前的版本执行下面指令 mysqld -remove(3) 启动MySQL服务 // 启动mysql服务 net start …...
C# IList 与List区别二叉树的层序遍历
IList 接口: IList 是一个接口,定义了一种有序集合的通用 API。继承自 ICollection 接口和IEnumerable<T>,是所有泛型列表的基接,口它提供了对列表中元素的基本操作,如添加、删除、索引访问等。IList 不是一个具…...

助力android面试2024【面试题合集】
转眼间,2023年快过完了。今年作为口罩开放的第一年大家的日子都过的十分艰难,那么想必找工作也不好找,在我们android开发这一行业非常的卷,在各行各业中尤为突出。android虽然不好过,但不能不吃饭吧。卷归卷但是还得干…...

【动态规划】LeetCode-62.不同路径
🎈算法那些事专栏说明:这是一个记录刷题日常的专栏,每个文章标题前都会写明这道题使用的算法。专栏每日计划至少更新1道题目,在这立下Flag🚩 🏠个人主页:Jammingpro 📕专栏链接&…...

对 Vision Transformers 及其基于 CNN-Transformer 的变体的综述
A survey of the Vision Transformers and its CNN-Transformer based Variants 摘要1、介绍2、vit的基本概念2.1 patch嵌入2.2 位置嵌入2.2.1 绝对位置嵌入(APE)2.2.2 相对位置嵌入(RPE)2.2.3卷积位置嵌入(CPE) 2.3 注意力机制2.3.1多头自我注意(MSA) 2.4 Transformer层2.4.1 …...

MongoDB简介
数据库,顾名思义,是保存数据的地方。中华文化博大精深,短短3个文字,就定义了一个强大的数据管理和读写方式出来。数据库,管理的对象是数据。称为库,表示数据在库中有组织,相互之间有微妙的关系。…...
尚硅谷hadoop3.x课程部分资料文件下载,jdk,hadoopjar包
jdk文件百度云下载: 链接:https://pan.baidu.com/s/1MCiGRzOZY8rAFpRJwA3tdw 提取码:kphl hadoop的jar包: 最新版官网链接: Index of /dist/hadoop/core/stable (apache.org) 百度云下载,3.3.3版…...
vue el-radio-group多选封装及使用
基于Element UI库的Vue组件,实现了一个单选/多选框组合的效果,可以根据 type 属性的不同值来切换单选框(默认)和按钮式单选框/多选框。 创建组件index.vue (src/common-ui/radioGroup/index.vue) <template><el-radio-g…...

Kaggle-水果图像分类银奖项目 pytorch Densenet GoogleNet ResNet101 VGG19
一些原理文章 卷积神经网络基础(卷积,池化,激活,全连接) - 知乎 PyTorch 入门与实践(六)卷积神经网络进阶(DenseNet)_pytorch conv1x1_Skr.B的博客-CSDN博客GoogLeNet网…...

深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...

基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...

(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...