做JAVA的基本上都用过Spring,而IoC是Spring最核心的模块之一 。那IoC具体有什么用,Spring又是如何做到IoC的呢?这是本文要探索的话题 。
关于IoC什么是依赖?首先我们要明确“依赖”的概念 。所谓依赖,说直白点就是:A用了B,那A就依赖B 。换成程序世界的说法,如果A类里面出现了B类有关的代码(删除B类,编译A类会报错),那A就依赖B 。
打个比方,如果员工小明上班需要乘坐公交车,从家里到公司,那小明就依赖了公交车 。抽象成代码大概是这样:
public class Worker() {private String name;private String home;private String office;// 这里依赖了Bus类private Bus bus = new Bus();public void goToWork() {bus.take(name, home, office);}}复制代码
我们知道,依赖是一种耦合,而过多的耦合对程序是有害的,代码架构的本质,就是尽量去降低耦合 。试想一下,如果有一天员工小明升职加薪了,自己买了一辆小轿车代步,那凡是用到公交车的地方(比如上班、下班、接孩子、去商场、回家等等)岂不是需要修改代码,把Bus换成Car?如果某一天又想步行或者骑自行车呢?
文章插图
依赖倒置原则有了上面这个耦合的问题,于是业界的大佬们就想办法来解决这个问题 。设计模式六大原则里面有一个依赖倒置原则(Dependence Inversion Principle) 。
所谓依赖倒置原则,就是把原本耦合的A和B分开,中间加一个“抽象层” 。这样A只需要依赖抽象层,并不需要关心具体实现,只要它能完成自己需要的功能就行了 。而B也只依赖抽象层,实现这个功能就行了 。
如果A依赖B,我们称A为“上层”,B为“下层”,依赖倒置原则强调上层模块不应该依赖下层模块,两者应依赖其抽象 。
文章插图
仍然是上面员工小明的例子,其实他上班需要的并不是一个公交车,而是一个“交通工具”,这个交通工具可以是自行车、电动车、汽车等等,只要它能够把小明从家里带到公司就可以了 。我们改一下代码,变成了这样:
// 定义抽象类public interface Vehicle {void take(String name, String home, String office)}// 下层模块的细节,依赖抽象public class Bus implements Vehicle {@Overridepublic void take(String name, String home, String office) {// 实现细节}}public class Worker() {private String name;private String home;private String office;// 上层依赖了抽象类Vehicleprivate Vehicle vehicle = new Bus();public void goToWork() {vehicle.take(name, home, office);}} 复制代码
看到这段代码也许你会问:那这里Worker类里面不是还是要new一个Bus吗?那还是依赖了呀,以后如果换成其它交通工具仍然需要改代码 。别急,这就是我们下面会讲到的控制反转要解决的问题 。
控制反转控制反转(Inversion of Control)也就是我们说的IoC了 。要理解IoC,需要弄清楚到底什么被反转了?如何反转的?
上面的示例代码我们可以看到,即使我们引入了一个抽象层,但当一个Worker对象实际要使用Vehicle的时候,它还是必须得创建一个具体的对象,它可能是一个Bus,也可能是一个Car等 。但这样造成的问题是,依赖没有被彻底分离,两者还是存在耦合 。
那如何把它们彻底分离呢?答案就是把创建具体的Vehicle对象交给第三方去做 。这样Worker不用管如何创建的交通工具,而Bus也不用管自己是如何被创建的 。
想想我们生活中就有这样的例子,员工小明要坐公交车,他不用每次都自己去造一辆公交车吧,只需要去公交车站,等公交车公司的调度就行了 。而公交车工厂也跟小明没有任何关系,它的职责就是生产好公交车,交付给公交车公司 。通过引入了“公交车公司”这个第三方,小明和公交车工厂就完全解耦了 。
反转的是什么?对象如何获取它的依赖对象这件事情上,控制权反转了 。从自己创建,反转成了第三方管理 。
控制反转的进一步含义,不仅仅是获取,还有整个要依赖对象的生命周期(包括创建、维护、销毁等),控制权都被反转了 。从代码设计来看,一个简单的解决方式是,把具体的对象通过方法参数传进来,这样就不强依赖了:
public class Worker() {private String name;private String home;private String office;// 通过方法传进来public void goToWork(Vehicle vehicle) {vehicle.take(name, home, office);}} 复制代码
推荐阅读
- 饮食|关于维生素是否能帮助你减肥,这些真相你知道吗?
- spring框架之AOP面向切面编程
- 关于下一代智能手机的谈论 人工智能和云赋予手机完全个性化
- 看电视的利与弊
- 中国关于美人鱼的传说
- 韩信关于他与刘邦之间不同点的描述
- 交换机配置指南半分钟即可掌握关于SSL配置的内容
- 曹丕把曹彰杀了吗
- 关于人性的恶经典名句有哪些?
- 一文让你读懂JAVA.IO、字符编码、URL和Spring.Resource