java中的耦合与Spring IOC实现解耦

耦合

在软件工程中,对象之间的耦合度就是对象之间的依赖性。对象之间的耦合越高,即代表对象之间的依赖性很强,维护成本越高,因此对象的设计应使类和构件之间的耦合最小(高内聚低耦合),耦合在java中指的是,两个类之间的联系的紧密程度。

我们先来看一个例子:
在这里插入图片描述
这个例子中A类的方法参数使用到了B类,即A类依赖于B类,这是一种很强的耦合关系,因为A类的ATest方法只能使用B类,不能使用其它类了,另外,如果没有了B类,那么A类连编译都无法通过,这就是两个类耦合度很强的体现,我们在编程中应尽量少使用这种方式。

再看下面这个例子:
在这里插入图片描述
这个例子使用了面向接口编程,C类 与 A类、B类之间存在的是一种弱耦合关系,C类 的 put方法 的参数可以是 A类类型 也可以是 B类类型,没有A类或者没有B类,C类照样可以编译通过,正常运行,不像上面例子中的强耦合关系,必须是 某个类型, 其他类型皆不可的情形。我们可以得出结论:面向接口编程可以降低类之间的耦合性。在实际编程中我们应该尽量多使用面向接口编程来降低类与类之间的耦合性,增强代码的可扩展性。

类之间只能降低耦合性,无法消除耦合性!

“高内聚,低耦合”,用一句话概括就是写的代码尽可能专一的完成一个任务,且各段代码尽量模块化互相独立。

再举一个我们最常用的MVC三层架构关于类之间的耦合:
在这里插入图片描述
在service层我们需要使用dao层,通过在personServiceImpl类中创建了personDao接口的一个实现类对象,使得这两个类之间产生紧密的依赖关系,同样,如果没有personDaoImpl这个实现类,那么personServiceImpl这个类是无法通过编译的。在这里,我们创建对象的方式是直接new出一个我们需要的对象,这种方式将产生很强的耦合性,为什么这样说呢?
我们可以这样想,personDao是一个接口,会有很多的实现类,现在personServiceImpl类依赖的是它的其中某个实现类,那么下次我们如果要换成依赖另一个实现类呢?是不是就得重新new一个对象了,例如:personDao personDao=new personDaoImpl2();也可以说接口和实现类出现了强耦合。

spring为了降低这种耦合性,使用IOC容器来管理对象,当需要使用某个类,可以不再使用传统的new方式创建对象,而通过告诉spring容器,spring容器会在程序运行时查找你需要的类是否已在容器中,存在的话直接返回即可。
在这里插入图片描述
上面的例子就是spring的注解配置,我们要使用PersonDao接口的实现类,不直接通过new来创建,而是直接声明PersonDao类型变量,然后通过@Autowired注解配合@Qualifier注解从容器中拿到该具体的实现类对象,这样做的好处就是接口和实现类的耦合性不会很强,想要用接口的哪个实现类只需要修改@Qualifier注解的属性值即可。

补充一下自己的个人理解:个人认为通过new创建对象耦合度高的原因就是new出来的对象就被写死了,只能依赖那个对象,而使用Spring IOC容器或者面向接口编程却能不会被写死,想用哪个就直接去跟容器拿就好了。

什么是IOC?

IOC-Inversion of Control,即控制反转。它不是什么技术,而是一种设计思想。传统的创建对象的方法是直接通过 new 关键字,而 spring 则是通过 IOC 容器来创建对象,也就是说我们将创建对象的控制权交给了 IOC 容器。我们可以用一句话来概括 IOC:

   IOC 让程序员不在关注怎么去创建对象,而是关注对象创建之后的操作,把对象的创建、初始化、销毁等工作交给spring容器来做。

spring中,所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。

Spring IOC的底层是通过使用工厂模式+反射创建对象+配置文件实现的

  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
耦合的代码会导致以下问题: 1. 难以维护:当一个对象发生变化时,其他依赖于它的对象也需要相应地修改。如果代码存在大量耦合的关系,当一个对象发生改变时,需要在多个地方进行修改,增加了维护的难度和风险。 2. 难以扩展:如果一个对象被多个其他对象依赖,那么对该对象进行扩展或修改可能会影响到其他依赖它的对象。这使得系统的扩展变得困难,新功能的添加可能会导致意想不到的副作用。 下面以一个Spring Boot代码的例子来说明耦合的问题。 假设我们有一个控制器类 `UserController` 和一个服务类 `UserService`: ```java @RestController public class UserController { private UserService userService; public UserController() { userService = new UserService(); } @GetMapping("/users/{id}") public String getUser(@PathVariable String id) { return userService.getUserById(id); } } public class UserService { public String getUserById(String id) { // 获取用户逻辑 return "User: " + id; } } ``` 在上述代码,`UserController` 类直接创建了 `UserService` 的实例,并在 `getUser` 方法调用了 `userService.getUserById` 方法。这种紧密耦合的方式会导致以下问题: 1. 可维护性差:如果我们决定更改 `UserService` 的实现方式或者添加其他的依赖,那么我们需要修改 `UserController` 的代码。这种紧密耦合会导致修改的范围扩大,增加了代码的维护成本。 2. 难以进行单元测试:由于 `UserController` 直接依赖于 `UserService` 的具体实现,我们无法在单元测试轻松地模拟或替换 `UserService` 的行为。这使得单元测试变得困难,可能需要依赖于底层的数据库或其他外部资源。 为了解决这个问题,我们可以使用控制反转(IoC)和依赖注入(DI)来解耦代码。通过使用Spring Boot容器和相关注解,我们可以将对象的创建和管理交给容器处理,从而实现耦合的代码。详细的示例请查看之前的回答。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值