Java架构直通车——彻底了解DIP、IOC与DI之间的关系

本来这个文章是面试准备:Spring/Spring MVC常见面试题汇总的一个小问题,但是觉得需要扩充的内容太多,就单独写成一个文章了。

DIP、IOC与DI之间的关系

在这里插入图片描述

DIP

原本的依赖是高层依赖于底层。假设我们设计一辆汽车:先设计轮子,然后根据轮子大小设计底盘,接着根据底盘设计车身,最后根据车身设计好整个汽车。这里就出现了一个“依赖”关系:汽车依赖车身,车身依赖底盘,底盘依赖轮子。
在这里插入图片描述
这样做的坏处是什么呢? 可维护性很低 。假设设计完工之后,上司却突然说根据市场需求的变动,要我们把车子的轮子设计都改大一码。这下我们就蛋疼了:因为我们是根据轮子的尺寸设计的底盘,轮子的尺寸一改,底盘的设计就得修改;同样因为我们是根据底盘设计的车身,那么车身也得改,同理汽车设计也得改——整个设计几乎都得改!

我们现在换一种思路:底层依赖于高层高层建筑决定需要什么,底层去实现这样的需求。我们先设计汽车的大概样子,然后根据汽车的样子来设计车身,根据车身来设计底盘,最后根据底盘来设计轮子。这时候,依赖关系就倒置过来了:轮子依赖底盘, 底盘依赖车身, 车身依赖汽车。

实例参考

为了理解DIP概念,我们还是用上面汽车的例子。只不过这次换成代码。我们先定义四个Class,车,车身,底盘,轮胎。然后初始化这辆车,最后跑这辆车。代码结构如下:
在这里插入图片描述

现在假设经理说要该轮胎的大小,把它的尺寸变成动态的,而不是一直都是30。我们需要这么改:(牵一发而动全身)

在这里插入图片描述

如果采用依赖倒置的方式是怎么设计的呢?
在这里插入图片描述
这里我们再把轮胎尺寸变成动态的,同样为了让整个系统顺利运行,我们需要做如下修改:

在这里插入图片描述
这里我们是采用的构造函数传入的方式进行的 依赖注入DI 。其实还有另外两种方法:Setter传递接口传递

IOC

IoC,Inversion of Control(控制反转)。

控制反转(Inversion of Control) 就是依赖倒置原则的一种代码设计的思路。把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。这个控制权从从程序代码本身转移到了外部容器。

这样对象与对象之间是松耦合、便于测试、功能可复用(减少对象的创建和内存消耗),使得程序的整个体系结构可维护性、灵活性、扩展性变高。
优点:

  1. 依赖注入把应用的代码量降低。
  2. 它使应用容易测试,单元测试不再需要单例和JNDI查找机制。
  3. 最小的代价和最小的侵入性使松散耦合得以实现。
  4. IOC容器支持加载服务时的饿汉式初始化和懒加载。
  • spring 提供了三种主要的方式来配置 IoC 容器中的 bean
    基于 XML 文件配置
    基于注解配置
    基于注解 + java 代码显式配置、

实例参考

在这里插入图片描述
显然你也应该观察到了,因为采用了依赖注入,在初始化的过程中就不可避免的会写大量的new。这里IoC容器就解决了这个问题。这个容器可以自动对你的代码进行初始化,你只需要维护一个Configuration(可以是xml可以是一段代码),而不用每次初始化一辆车都要亲手去写那一大段初始化的代码。这是引入IoC Container的第一个好处。

IoC Container的第二个好处是:我们在创建实例的时候不需要了解其中的细节。在上面的例子中,我们自己手动创建一个车instance时候,是从底层往上层new的,这个过程中,我们需要了解整个Car/Framework/Bottom/Tire类构造函数是怎么定义的,才能一步一步new/注入。
在这里插入图片描述
而IoC Container在进行这个工作的时候是反过来的,它先从最上层开始往下找依赖关系,到达最底层之后再往上一步一步new(有点像深度优先遍历):
在这里插入图片描述
这里IoC Container可以直接隐藏具体的创建实例的细节,在我们来看它就像一个工厂:
在这里插入图片描述

DI

DI依赖注入,是 IoC 实现的一种方式(还有一种是依赖查找)。通过依赖注入机制,简单的配置即可注入需要的资源,完成自身的业务逻辑,不需要关心资源的出处和具体实现。

DI注入的方式:
spring支持setter注入和构造器注入,通常是由构造器注入来注入必须的依赖关系,对于可选的依赖关系,则setter注入是更好的选择。setter注入需要类提供无参构造器或者无参的静态工厂来创建对象。

面试总结:什么是IOC?

IOC是依赖倒置原则的一种思路,他将由传统代码负责创建对象交由容器进行统一的装配和管理,这就使得控制权从代码本身转移到了容器,这就是IOC的控制反转。

而IOC的一种实现方式是依赖注入,前面说了IOC他是依赖倒置原则的思路,所以他的依赖关系是底层依赖于高层,底层是通过构造器注入或者setter注入到高层的,这就需要去关注底层的实现,而DI则为我们屏蔽了这个过程,通过简单的Configuration,无需去关注对象是怎么一步步实现的,就可以拿到对象。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值