什么是IoC控制反转思想?
IoC(Inversion of Control)即控制反转,这里的控制是代表控制权的意思,IoC是一种编程思想,旨在降低代码之间的耦合度、降低代码的维护成本。这种思想的具体内容就是将对象的创建和管理交给外部的容器和框架,不再是由对象的调用者去new一个对象。在这个过程中,对象的创建和管理的权力由传统的对象调用者转移到了外部的容器和框架,即对象的控制权发生了反转。
目录
一.什么是IoC?
IoC(Inversion of Control)即控制反转,这里的控制是代表控制权的意思,IoC是一种编程思想,旨在降低代码之间的耦合度、降低代码的维护成本。
这种思想的具体内容就是将对象的创建和管理交给外部的容器和框架,不再是由对象的调用者去new一个对象。在这个过程中,对象的创建和管理的权力由传统的对象调用者转移到了外部的容器和框架,即对象的控制权发生了反转。
这样说明可能还是不够易于理解,我们拿制造小汽车这样的一个例子来举例说明:
对于传统的非IoC的思想来说,我们先设计轮⼦(Tire),然后根据轮⼦的⼤⼩设计底盘(Bottom),接着根据底盘设计⻋⾝(Framework),最后根据⻋⾝设计好整个汽⻋(Car)。这⾥就出现了⼀个"依赖"关系:汽⻋依赖⻋⾝,⻋⾝依赖底盘,底盘依赖轮⼦。
用Java代码模拟这个过程如下,要设计汽车就需要使用车身的框架、要得到车身的框架就需要使用底盘、要得到地盘就需要使用轮胎。
package com.luming.iocdemo;
public class NewCarExample {
public static void main(String[] args) {
Car car = new Car();
car.run();
}
/**
* 汽⻋对象
*/
static class Car {
private Framework framework;
public Car() {
framework = new Framework();
System.out.println("Car init....");
}
public void run() {
System.out.println("Car run...");
}
}
/**
* ⻋⾝类
*/
static class Framework {
private Bottom bottom;
public Framework() {
bottom = new Bottom();
System.out.println("Framework init...");
}
}
/**
* 底盘类
*/
static class Bottom {
private Tire tire;
public Bottom() {
this.tire = new Tire();
System.out.println("Bottom init...");
}
}
/**
* 轮胎类
*/
static class Tire {
// 尺⼨
private int size;
public Tire() {
this.size = 17;
System.out.println("轮胎尺⼨:" + size);
}
}
}
但这样的代码有一个很大的问题,假如用户的需求变得复杂的,用户想要依据自己的喜好来选择轮胎的大小,那么就需要在轮胎Tire中设置一个参数来接收用户喜好的参数,但是Tire的调用者Bottom却没有这个参数给Tire传递,因此就需要修改Bottom的源码添加一个参数列表来接收上层传递的参数,Bottom的调用者Framework也面临着这样的困境,因此Framework的源码也得修改,就这样参数每一次向下传递的时候都需要相关类对象的源码,类与类之间的耦合度非常的高,牵一发而动全身,一旦面临新的需求就需要大篇幅的修改源码,这很显然对开发者是并不友好的。
在上⾯的程序中,我们是根据轮⼦的尺⼨设计的底盘,轮⼦的尺⼨⼀改,底盘的设计就得修改。同样因为我们是根据底盘设计的⻋⾝,那么⻋⾝也得改,同理汽⻋设计也得改, 也就是整个设计⼏乎都得改。
▐ IoC核心思想
那倘若我们换一种思路呢?我们先设计汽⻋的⼤概样⼦,然后根据汽⻋的样⼦来设计⻋⾝,根据⻋⾝来设计底盘,最后根据底盘来设计轮⼦。这时候,依赖关系就倒置过来了:轮⼦依赖底盘, 底盘依赖⻋⾝,⻋⾝依赖汽⻋。这就体现了“反转”。
这就类似我们打造⼀辆完整的汽⻋,如果所有的配件都是⾃⼰造,那么当客⼾需求发⽣改变的时候,⽐如轮胎的尺⼨不再是原来的尺⼨了,那我们要⾃⼰动⼿来改了,但如果我们是把轮胎外包出去,那么即使是轮胎的尺⼨发⽣变变了,我们只需要向代理⼯⼚下订单就⾏了,我们⾃⾝是不需要出⼒的。
因为我们一开始设计出了汽车的大概样子,倘若用户需要19寸的轮子,那我们就问工厂要一个19寸轮胎对应的车身框架Framework,对于车身框架也是同样,问工厂要一个对应兼容的底盘Bottom即可,对于用户差异的需求实现全都在交付给工厂,工厂集中存放了各种各样需求对应的组件(对象)。
我们对比一下俩种思想中对于对象的创建:
- 传统思想:对象的调用者来创建类对象
- IoC思想:对象由第三方工厂代理创建
public class IocCarExample {
public static void main(String[] args) {
Tire tire = new Tire(20);
Bottom bottom = new Bottom(tire);
Framework framework = new Framework(bottom);
Car car = new Car(framework);
car.run();
}
static class Car {
private Framework framework;
public Car(Framework framework) {
this.framework = framework;
System.out.println("Car init....");
}
public void run() {
System.out.println("Car run...");
}
}
static class Framework {
private Bottom bottom;
public Framework(Bottom bottom) {
this.bottom = bottom;
System.out.println("Framework init...");
}
}
static class Bottom {
private Tire tire;
public Bottom(Tire tire) {
this.tire = tire;
System.out.println("Bottom init...");
}
}
static class Tire {
private int size;
public Tire(int size) {
this.size = size;
System.out.println("轮胎尺⼨:" + size);
}
}
}
代码经过以上调整,⽆论底层类如何变化,整个调⽤链是不⽤做任何改变的,这样就完成了代码之间的解耦,从⽽实现了更加灵活、通⽤的程序设计了。
- 在传统的代码中对象创建顺序是:Car -> Framework -> Bottom -> Tire
- 改进之后解耦的代码的对象创建顺序是:Tire -> Bottom -> Framework -> Car
我们发现了⼀个规律,通⽤程序的实现代码,类的创建顺序是反的,传统代码是 Car 控制并创建了Framework,Framework 创建并创建了 Bottom,依次往下;⽽改进之后的控制权发⽣的反转,不再是使⽤⽅对象创建并控制依赖对象了,⽽是把依赖对象注⼊将当前对象中,依赖对象的控制权不再由当前类控制了。这样的话, 即使依赖类发⽣任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是 IoC 的实现思想。
本次的分享就到此为止了,希望我的分享能给您带来帮助,创作不易也欢迎大家三连支持,你们的点赞就是博主更新最大的动力!如有不同意见,欢迎评论区积极讨论交流,让我们一起学习进步!有相关问题也可以私信博主,评论区和私信都会认真查看的,我们下次再见
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)