Java:控制反转(IoC)与依赖注入(DI)

01、紧耦合

在我们编码的过程中,通常都需要两个或者更多的类通过彼此的合作来实现业务逻辑,也就是说,某个对象需要获取与其合作对象的引用,如果这个获取的过程需要自己实现,代码的耦合度就会高,维护起来的成本就比较高。

我们来通过实战模拟一下。假如老王是少林寺的主持,他想让小二和尚去扫达摩院的地,代码可以这样实现。

小二类的代码如下所示: public class Xiaoer { public void saodi() { System.out.println("小二我在扫达摩院的地"); } }

老王类的代码如下所示: public class Laowang { public void mingling() { new Xiaoer().saodi(); } }

测试类的代码如下所示: public class Test { public static void main(String[] args) { Laowang laowang = new Laowang(); laowang.mingling(); } }

Laowang 类的 mingling 方法中使用 new 关键字创建了一个 Xiaoer 类的对象——这种代码的耦合度就很高,维护起来的成本就很高,为什么这么说呢?

某一天,达摩院的地又脏了,老王主持想起了小二和尚,可小二和尚去练易筋经了,让谁去扫地呢,老王主持想起了小三和尚,于是 Laowang 类就不得不重新下一个新的命令,于是代码变成了这样:

public class Xiaosan {
public void saodi() { System.out.println("小三我在扫达摩院的地"); } } public class Laowang { public void mingling() { new Xiaoer().saodi(); }

public void mingling1() {
    new Xiaosan().saodi();
}

} 假如小三和尚去挑水了,老王主持没准要下命令给小四和尚去扫达摩院的地。这样下去的话,Laowang 这个类会疯掉的。

老王主持觉得自己堂堂一届高僧,下个扫地的命令竟然这样麻烦,他觉得很不爽。

02、控制反转

我们得替老王主持想个办法对不对?

不如把这个扫地的差事交给老王的师弟老方吧,老方负责去叫小二和尚还是小三和尚还是小四和尚去执行老王主持的命令。代码可以这样实现。

定义一个扫地和尚的接口,代码如下所示: public interface Heshang { void saodi(); }

小二类的代码修改如下所示: public class Xiaoer implements Heshang {

[@Override](https://my.oschina.net/u/1162528)
public void saodi() {
    System.out.println("小二我在扫达摩院的地");
}

public boolean isYijinjing() {
    // 星期三的时候小二和尚要练易筋经
    return false;
}

}

小三类的代码修改如下所示: public class Xiaosan implements Heshang { @Override public void saodi() { System.out.println("小三我在扫达摩院的地");
} }

老方类的代码如下所示: public class Laofang { public static Heshang getSaodiseng() { Xiaoer xiaoer = new Xiaoer(); if (xiaoer.isYijinjing()) { return new Xiaosan(); } return xiaoer; } } 如果老方确认小二和尚在练易筋经,就叫小三和尚。

老王类的代码修改如下所示: public class Laowang { public void mingling() { Laofang.getSaodiseng().saodi(); } }

测试类的代码不改变,如下所示: public class Test { public static void main(String[] args) { Laowang laowang = new Laowang(); laowang.mingling(); } }

老王现在是不是省心多了,他只管下命令,该叫谁去扫达摩院的地由他师弟老方去负责。

我们替老王想的这个办法就叫控制反转(Inversion of Control,缩写为 IoC),它不是一种技术,而是一种思想——指导我们设计出松耦合的程序。

控制反转从词义上可以拆分为“控制”和“反转”,说到控制,就必须找出主语和宾语,谁控制了谁;说到反转,就必须知道正转是什么。

你看,在紧耦合的情况下,老王下命令的时候自己要通过 new 关键字创建依赖的对象(小二和尚或者小三和尚);而控制反转后,老王要找的扫地和尚由他师弟老方负责,也就是说控制权交给了老方,是不是反转了呢?

03、依赖注入

依赖注入(Dependency Injection,简称 DI)是实现控制反转的主要方式:在类 A 的实例创建过程中就创建了依赖的 B 对象,通过类型或名称来判断将不同的对象注入到不同的属性中。大概有 3 种具体的实现形式:

1)基于构造函数。

实现特定参数的构造函数,在新建对象时传入所依赖类型的对象。

老王类的代码修改如下所示: public class Laowang {
private Heshang saodiseng;

public Laowang(Heshang saodiseng) {
    this.saodiseng = saodiseng;
}
public void mingling() {
   this.saodiseng.saodi();
}

}

测试类的代码修改如下所示: public class Test {
public static void main(String[] args) { Laowang laowang = new Laowang(new Xiaosan()); laowang.mingling(); } } 这时候,控制权掌握在测试类的手里,它决定派小二和尚还是小三和尚去执行老王的扫地命令。

2)基于 set 方法。

实现特定属性的 public set 方法,让外部容器调用传入所依赖类型的对象。

老王类的代码修改如下所示: public class Laowang {
private Heshang saodiseng;

public Heshang getSaodiseng() {
    return saodiseng;
}

public void setSaodiseng(Heshang saodiseng) {
    this.saodiseng = saodiseng;
}

public void mingling() {
   this.getSaodiseng().saodi();
}

}

测试类的代码修改如下所示: public class Test {
public static void main(String[] args) { Laowang laowang = new Laowang(); Xiaosan xiaosan = new Xiaosan(); laowang.setSaodiseng(xiaosan); laowang.mingling(); } } 这时候,控制权仍然掌握在测试类的手里,它决定派小二和尚还是小三和尚去执行老王的扫地命令。

3)基于接口。

实现特定接口以供外部容器注入所依赖类型的对象,这种做法比较构造函数和 set 方法更为复杂,这里就此略过。

可能有人会把控制反转等同于依赖注入,但实际上它们有着本质上的不同:控制反转是一种思想,而依赖注入是实现控制反转的一种形式。

04、Spring 框架

当我们搞清楚控制反转和依赖注入的概念后,就可以顺带了解一下大名鼎鼎的 Spring 框架。控制反转是 Spring 框架的核心,贯穿始终。Spring 中依赖注入有两种实现方式:set 方式(传值方式)和构造器方式(引用方式)。

首先,我们需要在 pom.xml 文件中加入 Spring 的依赖项,代码如下所示: <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.2.RELEASE</version></dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.2.RELEASE</version> </dependency>

其次,我们将 Laowang 类修改为如下内容: public class Laowang { private Heshang saodiseng;

public Laowang(Heshang saodiseng) {
    this.saodiseng = saodiseng;
}
public void mingling() {
   this.saodiseng.saodi();
}

}

然后,我们创建一个 Spring 的配置文件 application.xml,内容如下所示:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="laowang" class="com.cmower.java_demo.ioc.Laowang"> <constructor-arg ref="saodiseng" /> </bean> <bean id="saodiseng" class="com.cmower.java_demo.ioc.Xiaosan" /></beans>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="laowang" class="com.cmower.java_demo.ioc.Laowang"> <constructor-arg ref="saodiseng" /> </bean>

<bean id="saodiseng" class="com.cmower.java_demo.ioc.Xiaosan" />

</beans>

通过元素配置了两个对象,一个老王主持,一个小三和尚,使用 元素将小三和尚作为老王主持的构造参数。

准备工作完成以后,我们来测试一下,代码示例如下: public class Test { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("application.xml"); Laowang laowang = (Laowang) context.getBean("laowang"); laowang.mingling(); } } 你看,我们将控制权交给了 IoC 框架 Spring,这样也可以完美的解决代码耦合度较紧的问题。

05、总结

1)控制反转是一种在软件工程中解耦合的思想,把控制权交给了第三方,在运行的时候由第三方决定将具体的依赖对象“注入”到调用类的对象中。

2)依赖注入可以作为控制反转的一种实现方式,将实例变量传入到一个对象中去。

3)通过 IoC 框架,类 A 依赖类 B 的强耦合关系可以在运行时通过容器建立,也就是说把创建 B 实例的工作移交给容器,类 A 只管使用就可以。

来源:http://www.1994july.club/

原文地址:https://www.cnblogs.com/1994july/p/12178099.html

时间: 2024-11-13 09:57:59

Java:控制反转(IoC)与依赖注入(DI)的相关文章

iOS控制反转(IoC)与依赖注入(DI)的实现

背景 最近接触了一段时间的SpringMVC,对其控制反转(IoC)和依赖注入(DI)印象深刻,此后便一直在思考如何使用OC语言较好的实现这两个功能.Java语言自带的注解特性为IoC和DI带来了极大的方便,要在OC上较好的实现这两个功能,需要一些小小的技巧. 控制反转和依赖注入 控制反转 简单来说,将一个类对象的创建由手动new方式改为从IOC容器内获取,就是一种控制反转,例如我们现在要创建一个ClassA类,则常规方法为 ClassA *a = [ClassA new]; 如果使用控制反转,

控制反转IOC与依赖注入DI

1. IoC理论的背景我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑. 图1:软件系统中耦合的对象 如果我们打开机械式手表的后盖,就会看到与上面类似的情形,各个齿轮分别带动时针.分针和秒针顺时针旋转,从而在表盘上产生正确的时间.图1中描述的就是这样的一个齿轮组,它拥有多个独立的齿轮,这些齿轮相互啮合在一起,协同工作,共同完成某项任务.我们可以看到,在这样的齿轮组中,如果有一个齿轮出了问题,就可能会影响到整个齿轮组

控制反转IOC与依赖注入DI - 理论篇

学无止境,精益求精 十年河东十年河西,莫欺少年穷 昨天是五一小长假归来上班的第一天,身体疲劳,毫无工作热情.于是就看看新闻,喝喝茶,荒废了一天 也就在昨天,康美同事张晶童鞋让我学习下IOC的理论及实现,毕竟是之前的好同事,好朋友,我也就抽时间百度了很多资料 在查阅网上资料的过程中,我发现大多技术篇幅都是IOC的代码实现,并没有一篇介绍IOC理论的篇幅!这显然不是我想要的. 我知道要想搞明白IOC,就必须要弄明白什么是IOC(控制反转)?为什么叫IOC(控制反转)?为什么之后又可以称为DI(依赖注

控制反转(Ioc)和依赖注入(DI)

控制反转IOC, 全称 “Inversion of Control”.依赖注入DI, 全称 “Dependency Injection”. 面向的问题:软件开发中,为了降低模块间.类间的耦合度,提倡基于接口的开发,那么在实现中必须面临最终是有“谁”提供实体类的问题.(将各层的对象以松耦合的方式组织起来,各层对象的调用面向接口.) 当一个类的实例需要另一个类的实例协助时,在传统的程序设计过程中,通常有调用者来创建被调用者的实例. 然后,采用依赖注入原则,创建被调用者的实例的工作不再由调用者完成,而

控制反转(IoC)与依赖注入(DI)

1.控制反转(Inversion of Control)与依赖注入(Dependency Injection) 控制反转即IoC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理.所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器. IoC是一个很大的概念,可以用不同的方式来实现.其主要实现方式有两种:<1>依赖查找(Dependency Lookup):容器提供回调接口和上下文环

spring中的控制反转IoC和依赖注入DI

原文:http://blog.163.com/[email protected]/blog/static/50639037200721345218382/ IoC(Inversion of Control),这是spring的核心,贯穿始终.所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关 系.这是什么意思呢,举个简单的例子,我们是如何找女朋友的?常见的情况是,我们到处去看哪里有长得漂亮身材又好的mm,然后打听她们的兴趣爱好.qq 号.电话号.手机号.

Spring入门--控制反转(IOC)与依赖注入(DI)

    1.控制反转(Inversion of Control)与依赖注入(Dependency Injection) 控制反转即IoC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理.所谓的"控制反转"概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器. IoC是一个很大的概念,可以用不同的方式来实现.其主要实现方式有两种:<1>依赖查找(Dependency Lookup)

AutoFac (控制反转IOC 与依赖注入DI)

绝世好文  转:http://blog.csdn.net/fanbin168/article/details/51293218 1 IOC概念(很重要) 项目 先引入AutoFac 和AutoFac MVC两个程序集到项目中 然后我们在MVC(UI层)的App_Start文件夹下创建一个AutoFacConfig.cs类 [csharp] view plain copy using System; using System.Collections.Generic; using System.Li

控制反转IOC的依赖注入方式

引言: 项目中遇到关于IOC的一些内容,因为和正常的逻辑代码比较起来,IOC有点反常.因此本文记录IOC的一些基础知识,并附有相应的简单实例,而在实际项目中再复杂的应用也只是在基本应用的基础上扩展而来的.本文目的两个,一是记录学习过程,以便将来温故:二是请大牛对小弟指点一二. 概念: 控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心. 控制反转一般分为两种类型,依赖注入(Dependen

依赖耦合、解耦、控制反转(IOC)、依赖注入

随着net的深入学习,出现了很多概念性的东西需要理解,现在统一记录一下. 1.依赖:现阶段在任何一个有请求作用的系统,都会出现A类调用B类的情况,这时候A类就依赖于B类,A类和B类存在依赖关系. 2.耦合.解耦:A类依赖于B类,这时对B类调用,一般通过A a=new B();的形式,不过这个时候如果B类重构(例如:增加了一个参数param1),要保证A类的正确使用,则必须重新new:A a=new B(param1); 则此时A类和B类就是耦合关系.不过带来了很多的不方便之处,如果B类频繁变动,