Java 你知道什么是耦合、如何解(降低)耦合

作者:怪咖软妹@ 时间:2022-03-23 08:44:19 

什么是耦合性

耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、数据传递关系。模块间联系越多,其耦合性越强,同时表明其独立性越差( 降低耦合性,可以提高其独立性)。

什么是程序间的耦合

假如:当我去new一个对象的时候,而这个对象不存在,这个时候程序会报编译时异常,也就意味着程序连运行都运行不了,我们可以理解为他们的耦合度较高。

如何解耦

我们可以利用Java的反射技术,通过类定名,来进行反射创建对象,这个时候我们可以成功的避免编译时异常,并且保证了项目在这个时候还能正常运行。

工厂模式解耦

在实际开发中我们可以把三层的对象都使用配置文件配置起来,当启动服务器应用加载的时候,让一个类中的方法通过读取配置文件,把这些对象创建出来并存起来。在接下来的使用的时候,直接拿过来用就好了。那么,这个读取配置文件,创建和获取三层对象的类就是工厂。

案例

早期我们的 JDBC 操作,注册驱动时,我们为什么不使用 DriverManager 的 register 方法,而是采用 Class.forName 的方式?


public class JdbcDemo1 {
public static void main(String[] args) throws Exception {
//1.注册驱动
//DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接
//3.获取预处理 sql 语句对象
//4.获取结果集
//5.遍历结果集
}
}

原因就是:

我们的类依赖了数据库的具体驱动类(MySQL),如果这时候更换了数据库品牌(比如 Oracle),需要修改源码来重新数据库驱动。这显然不是我们想要的。

解决思路:

当是我们讲解 jdbc 时,是通过反射来注册驱动的,代码如下:

Class.forName("com.mysql.jdbc.Driver");//此处只是一个字符串

此时的好处是,我们的类中不再依赖具体的驱动类,此时就算删除 mysql 的驱动 jar 包,依然可以编译(运行就不要想了,没有驱动不可能运行成功的)。同时,也产生了一个新的问题,mysql 驱动的全限定类名字符串是在 java 类中写死的,一旦要改还是要修改源码。解决这个问题也很简单,使用配置文件配置。

以上只是说的解耦的一种思维,方便大家理解。

解耦的核心思想:若要减少代码的耦合度,一定要尽量做到各个功能的代码不能交叉编写,编写封闭的代码。

解耦合

广大程序猿同胞,经常会看到“解耦合”,也有很多人,会用这个词来装X,但是,实际真正能理解的人,并不多。接下来,带大家深入浅出的走一遍,如何解耦合。

首先,我们要知道,为什么要解耦合:通常,我们做一个项目,会用到很多基础功能块,比如xxx通信协议,xxxView等等,我们会把这种功能块封装成一个库,如果这个库,只能在这个指定的项目运行,这就叫高耦合,这就导致了,如果下次再次遇到一个类似的项目,需要用到同样功能的功能块时,你会要做很多重复工作。假设,每次使用json时,你都要对json库进行改造,那将会是一个晴天霹雳。

但是,事与愿违,有些情况,还真的不太好解耦。

这里,我们先举个栗子,比如排序

一个排序功能,对于大部分比较初级的程序猿来说,可能会写成这样:


sort(List<Integer> list)

这样就导致了一个问题所在,这个方法只能排序int型数据,如果下一个项目,需要用到对String进行排序,那就很尴尬,感觉明明要成功了,但是又差一点。对,就是差这一点,就是代码解耦的关键。

我们先要明确,我们需要做的是排序功能,在这个过程中,我们不可避免的需要使用2个数据的大小对比,而这个数据,可能是任何数据,也就是说,排序算法,我们是可以确定下来,做成不动的库,但是有一个数据大小匹配是我们无法做到的,或者说是库的耦合点,那怎么办呢?

我们就让使用我们这个功能块的人,告诉我们就行啦。

下面,我们参考Android库里面,有个排序的api


Collections.sort(List<T> list, Comparator<? super T> c);

这里,Comparator这个接口,就是使用者,需要实现,并且传递进去的接口。这样做,这个排序功能块就可以应用在任何场合,达到一次开发,受用终身的目的。是不是很神奇?

我们再举个栗子,socket

我们在开发时,经常会用到socket库,而socket最常用,最常用的一个功能就是:“连接->发送数据->接收数据->断开连接->回调结果”

所以,如果需要把这个流程,封装成一个功能块是很有意义的。

但是,这里有一个问题,是阻碍封装的,就是 "接收数据->断开连接",socket读取数据时,是一个inputStream,是个流,也就是说,其实,你并不知道,数据怎么样才算接收 完整/完毕

可能,有的协议,是通过头2个字节来判断整个数据长度

可能,有的协议是有帧头,帧尾,转义符来判断整个数据长度

……

这让我们很头疼,那怎么 解决了,既然无法知道的东西,就让应用程序来告诉你呗。和上面一样,传入一个协议实现呗:


public interface UnZipDataAction{
// 返回null,表示未接收完全,继续接收,返回完整的byte[]就认为是已经接收完毕,把结果返回给应用,并且断开连接
byte[] getRealData(byte[] recvData); ErrorCode getErrorCode(); }

这样,我们就把“连接->发送数据->接收数据->断开连接->回调结果”整个流程封装成了通用的功能块了。

解耦总结来说就是:你能知道的东西就写死,不知道但是又必须知道的东西,就让应用程序来告诉你,在java里面叫接口,在有些语言(OC, swift, C/C++)里面叫做代码段。

来源:https://blog.csdn.net/weixin_43888891/article/details/108289642

标签:Java,耦合,降低
0
投稿

猜你喜欢

  • android压力测试命令monkey详解

    2023-06-17 00:36:29
  • Java使用Preference类保存上一次记录的方法

    2023-05-08 01:49:14
  • Java实现断点下载服务端与客户端的示例代码

    2022-07-25 14:16:17
  • Java多线程编程中使用Condition类操作锁的方法详解

    2023-10-19 13:30:55
  • 分布式系统下调用链追踪技术面试题

    2023-11-25 05:55:00
  • SpringBoot集成FTP与SFTP连接池流程

    2021-12-27 12:22:26
  • 使用java实现BBS论坛发送邮件过程详解

    2022-12-19 16:58:30
  • 详解JAVA中static的作用

    2021-12-05 09:13:47
  • C#中在WebClient中使用post发送数据实现方法

    2023-05-01 00:03:54
  • Java SpringBoot高级用法详解

    2021-07-03 18:27:09
  • Java中ShardingSphere分库分表实战

    2023-11-24 09:20:37
  • Spring Boot实现异步请求(Servlet 3.0)

    2023-11-27 06:26:47
  • 关于SpringBoot中controller参数校验的使用

    2023-02-24 04:24:10
  • Android 实现签到足迹功能

    2023-06-21 15:16:24
  • Spring Boot自动注入的原理分析

    2023-03-29 04:19:44
  • 详解Spring-boot中读取config配置文件的两种方式

    2021-07-04 15:52:55
  • spring boot加载第三方jar包的配置文件的方法

    2023-03-02 22:45:13
  • hadoop实现grep示例分享

    2023-12-24 05:31:04
  • java获取系统路径字体、得到某个目录下的所有文件名、获取当前路径

    2023-11-29 14:39:23
  • 如何解决springboot读取配置文件的中文乱码问题

    2022-09-13 22:26:42
  • asp之家 软件编程 m.aspxhome.com