当前位置: 首页 > news >正文

掌握应用分层:高内聚低耦合的艺术

文章目录

  • 应用分层
  • 软件设计原则:高内聚低耦合
  • 项目示例
  • 应用分层的好处
  • 企业规范

应用分层

应用分层是一种软件开发设计思想, 它将应用程序分成N个层次, 这N个层次分别负责各自的功能, 多个层次之间协同提供完整的功能

常见的MVC设计模式, 就是应用分层的一种具体体现

为什么需要应用分层?

一开始,为了让项目快速上线,我们通常是不考虑分层的。但是随着业务越来越复杂,大量的代码混在一起,会出现逻辑不清晰、各模块相互依赖、代码扩展性差、牵一发而动全身等问题。

如何分层

MVC 就是把系统分成了 Model(模型), View(视图)和 Controller(控制器)三个层次,也就是将用户视图和业务处理隔离开,并且通过控制器连接起来,很好地实现了表现和逻辑的解耦,是一种标准的软件分层架构

在这里插入图片描述

目前主流的开发方式是 “前后端分离” 的方式, 后端开发工程师不再需要关注前端的实现, 所以对于Java后端开发者, 又有了一种新的分层架构: 把整体架构分为表现层、业务逻辑层和数据层。这种分层方式也称为"三层架构"

  1. 表现层: 是最靠近用户的一层,负责接收页面的请求,给页面响应数据
  2. 业务逻辑层: 负责处理业务逻辑
  3. 数据层: 负责存储和管理与应用程序相关的数据,负责业务数据的维护操作,包括增、删、改、查等操作

这三个部分, 在Spring的实现中, 均有体现:

  • Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。
  • Service:业务逻辑层。处理具体的业务逻辑。
  • Dao:数据访问层,也称为持久层。负责数据访问操作,包括数据的增、删、改、查

MVC 和 三层架构 的区别和联系

从概念上来讲, 二者都是软件工程领域中的架构模式.

  • MVC架构模式由三部分组成, 分别是: 模型(Model), 视图(View)和控制器(Controller)
  • 三层架构将业务应用划分为:表现层, 业务逻辑层, 数据访问层

在这里插入图片描述

MVC中, 视图和控制器合起来对应三层架构中的表现层,模型对应三层架构中的业务逻辑层, 数据层以及实体类

二者其实是从不同角度对软件工程进行了抽象

  • MVC模式强调数据和视图分离, 将数据展示和数据处理分开, 通过控制器对两者进行组合
  • 三层架构强调不同维度数据处理的高内聚和低耦合, 将交互界面, 业务处理和数据库操作的逻辑分开

角度不同也就谈不上互相替代了,在日常的开发中可以经常看到两种共存的情况,但是二者的目的是相同的, 都是"解耦,分层,代码复用"

软件设计原则:高内聚低耦合

  • 高内聚:实现某个功能的时候,如果和这个功能相关的代码是集中放在一起的,就认为是"高内聚"; 如果是散落在项目的各个文件,各个角落中就认为是"低内聚"。高内聚就非常方便找到并修改代码
  • 低耦合:软件中各个层、模块之间的依赖关联越小越好。修改一处代码, 其他模块的代码改动越少越好

内聚和耦合并没有必然的联系

  • 内聚描述的是模块内部的事情(也有可能是模块之间)
  • 耦合描述的是模块之间的事情

高内聚低耦合矛盾吗?

不矛盾, 高内聚指的是一个模块中各个元素之间的联系紧密程度, 低耦合指的是各个模块之间的紧密程度

这就好比一个企业, 包含很多部门, 各个部门之间的关联关系要尽可能的小, 一个部门发生问题, 要尽可能对降低对其他部门的影响, 这就是"低耦合"; 但是部门内部员工关系要尽量紧密,遇到问题一起解决克服,这叫做"高内聚"。又比如邻里邻居, 楼上漏水, 楼下遭殃, 就是"高耦合";一个家庭内部的关系越紧密越好,一个家庭成员生病, 其他成员帮忙照顾, 就叫"高内聚",一个家庭尽可能减少对另一个家庭的影响,就是"低耦合"

项目示例

在这里插入图片描述

  • controller包下是控制层: 接收前端发送的请求,对请求进行处理,并响应数据
import com.example.messagewall.model.MessageInfo;
import com.example.messagewall.service.MessageInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RequestMapping("/message")
@RestController
public class MessageController {@Autowiredprivate MessageInfoService messageInfoService;@RequestMapping(value = "/publish", method = RequestMethod.POST)public Boolean publish(@RequestBody MessageInfo messageInfo) {//添加到数据库messageInfoService.insert(messageInfo);return true;}@RequestMapping("/getList")public List<MessageInfo> getList() {//从数据库查return messageInfoService.query();}
}
  • service包下是业务逻辑层: 处理具体的业务逻辑
import com.example.messagewall.mapper.MessageInfoMapper;
import com.example.messagewall.model.MessageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class MessageInfoService {@Autowiredprivate MessageInfoMapper messageInfoMapper;public Integer insert(MessageInfo messageInfo) {return messageInfoMapper.insert(messageInfo);}public List<MessageInfo> query() {return messageInfoMapper.query();}
}
  • mapper包下是数据访问层: 负责数据访问操作,包括数据的增、删、改、查
import com.example.messagewall.model.MessageInfo;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;import java.util.List;@Mapper
public interface MessageInfoMapper {//添加留言@Insert("insert into message_info (`from`,`to`, `message`) values " +"(#{from}, #{to}, #{message})")Integer insert(MessageInfo messageInfo);//查询留言@Select("select * from message_info where delete_flag=0")List<MessageInfo> query();
}
  • model包下是实体类通常对应数据库中的表,包含该事物的属性(数据)和行为(方法),是数据存储和业务逻辑的基础载体
import lombok.Data;@Data
public class MessageInfo {private Integer id;private String from;private String to;private String message;private Integer deleteFlag;private String createTime;private String updateTime;
}

前端messagewall.html代码:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>留言板</title><style>.container {width: 350px;height: 300px;margin: 0 auto;/* border: 1px black solid; */text-align: center;}.grey {color: grey;}.container .row {width: 350px;height: 40px;display: flex;justify-content: space-between;align-items: center;}.container .row input {width: 260px;height: 30px;}#submit {width: 350px;height: 40px;background-color: orange;color: white;border: none;margin: 10px;border-radius: 5px;font-size: 20px;}</style>
</head><body><div class="container"><h1>留言板</h1><p class="grey">输入后点击提交, 会将信息显示下方空白处</p><div class="row"><span>谁:</span> <input type="text" name="" id="from"></div><div class="row"><span>对谁:</span> <input type="text" name="" id="to"></div><div class="row"><span>说什么:</span> <input type="text" name="" id="say"></div><input type="button" value="提交" id="submit" onclick="submit()"><!-- <div>A 对 B 说: hello</div> --></div><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script><script>$.ajax({type: "get",url: "/message/getList",success: function(messages) {if(messages!=null) {for(let message of messages) {var divE = "<div>"+message.from +"对" + message.to + "说:" + message.message +"</div>";$(".container").append(divE);}}}});function submit(){//1. 获取留言的内容var from = $('#from').val();var to = $('#to').val();var say = $('#say').val();if (from== '' || to == '' || say == '') {return;}//调用后端接口,发表留言$.ajax({type: "post",url: "/message/publish",contentType: "application/json",data: JSON.stringify({"from": from,"to": to,"message": say}),success: function(result) {if(result) {//成功//2. 构造节点var divE = "<div>"+from +"对" + to + "说:" + say+"</div>";//3. 把节点添加到页面上    $(".container").append(divE);//4. 清空输入框的值$('#from').val("");$('#to').val("");$('#say').val(""); } else {//失败alert("发布失败");}}});}</script>
</body></html>

配置文件application.yml:

spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=falseusername: rootpassword: '123456'driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:configuration: # 配置打印 MyBatis日志log-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-underscore-to-camel-case: true #配置驼峰自动转换

pom文件引入依赖部分:

    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.3</version></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency></dependencies>

按我配置的话,MySQL建库建表语句是这样的:

CREATE DATABASE IF NOT EXISTS mybatis_test;USE mybatis_test;CREATE TABLE message_info (id INT AUTO_INCREMENT PRIMARY KEY COMMENT '消息ID',`from` VARCHAR(255) COMMENT '发送者',`to` VARCHAR(255) COMMENT '接收者',message VARCHAR(255) COMMENT '消息内容',delete_flag TINYINT DEFAULT 0 COMMENT '逻辑删除标志:0=有效,1=无效',create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
);

全部搞定之后访问http://127.0.0.1:8080/messagewall.html就能交互啦!

应用分层的好处

  • 降低层与层之间的依赖, 结构更加明确, 利于各层逻辑的复用
  • 开发人员可以只关注整个结构中的其中某一层, 极大地降低了维护成本和维护时间
  • 可以很容易的用新的实现来替换原有层次的实现
  • 有利于标准化

企业规范

适用于多数企业, 均不做强制要求. 具体以所在企业为准

  1. 类名使用大驼峰风格,但以下情形例外:DO/BO/DTO/VO/AO
  2. 方法名、参数名、成员变量、局部变量统一使用小驼峰风格
  3. 包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词

常见命名风格介绍

  • 大驼峰: 所有单词首字母都需要大写, 又叫帕斯卡命名法, 比如: UserController
  • 小驼峰:除了第一个单词,其他单词首字母大写,比如: userController
  • 蛇形:用下划线 (_) 作为单词间的分隔符,一般小写,又叫下划线命名法,比如: user_controller
  • 串形:用短横线 (-) 作为单词间的分隔符,又叫脊柱命名法,比如: user-controller

相关文章:

  • Python with 关键字
  • 【FineDance】ModuleNotFoundError: No module named ‘pytorch3d‘
  • 数据目录:企业数据管理的核心引擎与最佳实践
  • Linux02
  • Linux Docker的环境配置与简单使用
  • 【Day48】
  • Docker 在尝试连接 Docker Hub 时遇到网络问题(超时)
  • 27 - ASPP模块
  • TI 毫米波雷达走读系列—— 3DFFT及测角
  • 疫菌QBD案例
  • Spring-rabbit重试消费源码分析
  • 低温对MOSFET的影响
  • SpringBoot打包运行原理和加载机制原理
  • 篇章六 论坛系统——业务开发——实现业务功能
  • JUC核心解析系列(四)——同步工具类 (Synchronizers)深度解析
  • Pytorch 卷积神经网络参数说明一
  • OSGI 是什么,有哪些具体应用、java8、9、10、11比较
  • uni-app项目实战笔记11--定义scss颜色变量方便页面引用
  • HarmonyOS 组件复用 指南
  • [直播推流] 使用 librtmp 库推流
  • 外国人可以在中国做网站吗/seo整站优化费用
  • 网站维护成本/百度收录提交入口网址
  • 天津做网站的公司排行/舆情分析报告范文
  • 非法期货做网站/5g站长工具seo综合查询
  • 外贸移动商城网站建设/网络推广免费平台
  • 网站怎么做下载网页/惠州市seo广告优化营销工具