什么是 Dao、Service、Controller、Util 和 Model ?

一,简介

我们做一个大项目会把项目分解成很多不不同的模块(Module),通常分为Dao,Service,Controller,Model,Utils。

有没有其实都可以,叫不叫这些名字也无妨,你要把Service的内容全写在Controller里也没问题,你要把Utils的工具函数分散在所有需要用的文件也Ok。但是久而久之,一堆人做一件事做的多了,就会形成这些约定俗成的部分,就好比形成了人行道,车行道,形成了红绿灯,当然这些终归还没有加进标准里去,所以你遵不遵守,都靠你自己。

所以,项目中是否包含这些模块或者单词,和你的项目结构是否完善一毛钱关系没有。但是当你的项目结构相对完善的时候,你会发现有这样一些角色的存在。

这一切都是为了实现高内聚度低耦合度,便于维护,也就是在软件生命周期中达到好的可用性以及总体上的低成本。但不应把这些当作教条,甚至不知道为了什么这样做。


二,项目分层

Model 模型

通常会有很多Model,就是数据库中的很多表定义。

Model 的作用就是数据的抽象,描述了一个数据的定义,Model的实例就是一组组的数据。整个系统都可以看成是数据的流动,既然要流动,就一定是有流动的载体。一条业务流就是对应一条或者多条数据流,

对于初学者而言,第一个要学会,就是建模,把业务逻辑映射成数据模型。


DAO 数据持久层

Dao一般而言,都是用来和底层数据库通信,负责对数据库的增删改查。

更直观一些,一个DAO对象 Article,包含 createArticle(), updateArticle(), deleteArticle()等方法。奇奇怪怪的SQL语句可以写在各个方法中。

这样可以解决,对象范例和关系范例这两大领域之间存在“阻抗不匹配”。这样分层也让controller 和 service 层更为干净。

本质上来说,DAO并不一定要和数据库有联系,DAO只是 Data Access Object(数据存取对象)的缩写,所以只要是把数据持久化包装成一个对象的访问(读写),这种对象都可以被称之为DAO,譬如,用JSON格式存到硬盘上。


Util 工具

Util就是工具,开发的过程中会产生许多奇奇怪怪的私有方法,有时候还都是重复的。这时候我们就可以把这些私有方法提取出来作为公用的方法。

像是URL编码或者解码,或是自创的加密签名算法等等。Util 代表他和业务逻辑是不相关的。通常命名也是ArticleUtil,CommentUtil之类的。

Util一般都有明确的输入和输出结果,都可以进行单元测试。


Service 服务

Service 比 Util 的概念大很多,它的重点是在于提供一个服务。这个服务可能包括一系列的数据处理,也有可能会调用多个Util,或者是调用别的服务。

技术上讲,一个 Service 可以调用其他 Service ,有人建议不要这样做,除非这个被调用的 Service 是公用的工具类。比如,有人给 Service 分了内外两层, 所有业务逻辑都放在 Service 里, 可复用的逻辑放在内层, 不复用的放在外层。这种情况会造成发布版本时,Service 变的不稳定。如果只允许 Controller 调用 Service,不允许 Service 互相调用,就可以避免这样的事。但是,这样遇到前后台统一业务逻辑的时候,代码要写两份。

综上所述,基本原则是 Service 不允许互相调用,保持 Controller 到 Service 到数据库的单线调用,然后在需要的时候打破这个规则,用 Service 调用 Service。

Service一般而言,都是包含有业务逻辑的,很少能做单元测试。


Controller 控制器

Controller 层是对客户端传来的数据做处理,传给 Service 层,然后把 Service 层产生的数据,返回给客户端。

比如,用户传了一个 pageSize,但是有可能传 null,这个时候你可以再进行一次转换成默认的10;然后调用Service 的方法,返回结果给到前端。


三,案例

案例一

阿里巴巴Java开发手册中的分层,甚至加入了DDD(领域模型)。

开放接口层:可直接封装 Service 接口暴露成 RPC 接口; 通过 Web 封装成 http 接口; 网关控制层等。

终端显示层:各个端的模板渲染并执行显示层。 当前主要是 velocity 渲染, JS 渲染, JSP 渲染,移动端展示层等。

Web 层:主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等。

Service 层:相对具体的业务逻辑服务层。

Manager 层:通用业务处理层,它有如下特征:

1)对第三方平台封装的层,预处理返回结果及转化异常信息;

2)对 Service 层通用能力的下沉,如缓存方案、 中间件通用处理;

3)与 DAO 层交互,对 DAO 的业务通用能力的封装。 

DAO 层:数据访问层,与底层 MySQL、 Oracle、 Hbase 进行数据交互。

外部接口或第三方平台:包括其它部门 RPC 开放接口,基础平台,其它公司的 HTTP 接口。

案例二

SpaceX-API是 r/SpaceX 社区开源的用于火箭、核心舱、太空舱、发射台和发射数据的开源 REST API。

SpaceX-API 技术细节:

部署在美国中部的 Linode 服务器上

在 Koa 框架中使用 Node.js

使用 Redis、Nginx 和 Cloudflare 进行内容缓存

使用 Jest 和 Supertest 进行测试

使用 Circle CI 进行持续集成 / 部署

所有数据都存储在 MongoDB Atlas 3 节点副本集集群中

夜间 mongodump 数据库备份

SpaceX-API 无视 MVC

下面是 SpaceX-API 的三个版本,v3版本的时候,还有点mvc的影子,路由和控制器还是分开的。其中有个 v4-experimental 版本,直接使用 go 语言写的。v4版本的时候,routes和controllers不见了,弄出来一个services,下面按版本和模块分文件夹,model和routes放在一个文件夹中。最新的版本应该是v5版本,services改名routes,按模块和版本分文件夹,models 挪出去,单独放在一个文件夹。

感觉 SpaceX-API 完全是想怎么写就怎么写,完全无视 MVC,中间还换了一次 go 语言。

 

案例三

这个星球上40%以上的网站使用的是 WordPress,完全没有用这种分层的概念。


实践

在实践中,很多小项目的业务逻辑都在Controller中进行处理,服务层只负责一些增删改查的方法。甚至增删改查也在控制器。这样会造成完全无法单元测试和后期维护性差。特别简单的项目和没有“以后”的项目可以这样做。


还有下面这样的观点:

“如果一个项目的生命周期比较长,要不要分层,项目一开始就要确定,这是架构师的职责。”

当项目达到一定规模,再重构,不要想着一个万全的设计。

“因为是面向数据库编程,但凡没有或者不怎么依赖数据库的程序,三层模型全面崩塌。”


看了 SpaceX-API,感觉自己玩,怎么来都可以;大家一起玩的话,商量着来。



参考:

https://www.zhihu.com/question/58410621

https://segmentfault.com/q/1010000018560036/a-1020000018615733

https://blog.csdn.net/qq_22771739/article/details/82344336

https://www.zhihu.com/question/58410621/answer/623496434

《阿里巴巴java开发手册》

https://github.com/r-spacex/SpaceX-API

https://www.zhihu.com/question/484268189/answer/2112084953

修改时间 2021-12-16

声明:本站所有文章,如无特殊说明或,均为原创发布。商业转载请联系作者获得授权,非商业转载请注明出处。本站所有图片如无特殊说明均为AI生成。
真诚赞赏,手留余香
赞赏
Node.js
browser-sync 浏览器自动刷新
2020-05-29
Node.js
JavaScript 数据验证模块 joi validator
2020-07-05
Jone
在什么样的花园里面,挖呀挖呀挖
种什么样的种子,开什么样的花
随机推荐
MySQL 删除逗号分隔字段中的某一个值
uni-app 实现暗黑模式/夜间模式/深色模式/暗黑主题(DarkMode)的几种方法
Debian11 安装笔记3:安装 MySQL 5.7
MySQL 使用 DATE_FORMAT() 和 FROM_UNIXTIME() 格式化时间
Git 放弃本地修改,强制和之前的某次提交同步
数据库中间表应该如何命名
Linux apt 命令
MySQL 表名预处理
MySQL 字符串截取函数 SUBSTRING_INDEX
Debian11 安装笔记2:编译安装PHP

微信联系我

夜间模式切换
回到顶部