什么是 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不允许互相调用,保持controller到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

修改时间 2021-11-11

真诚赞赏,手留余香
赞赏
随机推荐
PDO 使用预处理 LIMIT
安卓项目结构图
详解移动端网页适配开发
第一次用Photoshop CC 2018,第一次用Wacom数位板
php5.4环境下安装ECshop出现Strict Standards的解决方案
学之者生,用之者死——ACE历史与简评
API Rate Limiting 限速
NETFLIX纪录片: 设计的艺术 - 平面设计
Node.js Buffer(缓冲区)
Windows 2008 修改远程端口号