控制反转IoC简介
控制反转IoC简介
在实际的应用开发中,我们需要尽量避免和降低对象间的依赖关系,即降低耦合度。通常的业务对象之间都是互相依赖的,业务对象与业务对象、业务对象与持久层、业务对象与各种资源之间都存在这样或那样的依赖关系。但是如何才能做到降低类之间的依赖关系呢?这就是本文核心IoC需要解决的问题,下面从两大点具体介绍IoC:
(1)IoC与DI的基本概念
IoC(Inversion Of Control)即控制反转,其具体就是由容器来控制业务对象之间的依赖关系,而不是像传统方式中由代码来直接控制。控制反转的本质,是控制权由应用代码转到了外部容器,控制权的转移即是所谓的反转。控制权的转移带来的好处就是降低了业务对象之间的依赖程度,即实现了解耦。
IoC的实现策略有两种:
1)依赖查找:容器中的受控对象通过容器的API来查找自己所依赖的资源和协作对象。这种方式虽然降低了对象间的依赖,但是同时也使用到了容器的API,造成了我们无法在容器外使用和测试对象;
2)依赖注入(又称DI:Dependency Injection):对象只提供普通的方法让容器去决定依赖关系,容器全权负责组建的装配,它会把符合依赖关系的对象通过属性或者是构造函数传递给需要的对象。通过属性注射依赖关系的做法称为设值方法注入,将构造子参数传入的做法称为构造子注入。
依赖注入的好处如下:
查询依赖操作和应用代码分离;
受控对象不会使用到容器的特定的API,这样我们的受控对象可以搬出容器单独使用。
(2)IoC模式的实例讲解
IoC代表的是一种思想,也是一种开发模式,但它不是什么具体的开发方法。要理解IoC的概念,最简单的方式就是看它的实际应用,下面将着重介绍几个实例来讲解IoC的内涵。
我们在开发一个应用系统时,会需要开发大量的Java类,系统将会通过这些Java类之间的相互调用来产生作用。类与类之间的调用关系是系统类之间最直接的关系。因此,我们可以将系统中的类分为两类:调用者和被调用者。具体如下图一所示:

图一:调用方法问题
软件设计方法及设计模式的发展,共产生了三种类调用的方法:自己创建(new)、工厂模式(get)、外部注入(set),其中外部注入即为IoC/DI的模式。
无论是哪一种方法,都存在两个角色——调用者和被调用者。下面我们通过实例来讲解这三种方法的具体含义。首先,我们设定调用者对象为学生对象Student,被调用者对象为图书对象Book,要设计的代码功能是学生学习图书知识。
从GoF设计模式中,我们已经习惯一种思维编程方式:Interface Driven Design接口驱动,接口驱动有很多好处,可以提供不同灵活的子类实现,增加代码稳定和健壮性等。为了演示不同的方法在Student取得不同Book对象时的区别,我们采用接口来设计被调用者,实现的代码如下面三个类所示:
//Book接口类
public interface IBook{
public void learn();
}
//BookA实现类
public class BookA implements IBook{
public void learn(){
System.out.println("学习BookA");
}
}
//BookB实现类
public class BookB implements IBook{
public void learn(){
System.out.println("学习BookB");
}
}
其中IBook为图书的接口,它定义了一个学习接口learn(),并定义了两个图书类BookA和BookB来实现该接口,表示是两本不同的图书,其中learn()方法分别表示不同图书学习过程。
下面将从这三种方法讲解如何调用图书类:
1)new——自己创建
Student要学习BookA,就要定义一个learnBookA()的方法,并自己来创建BookA的对象;同样,要学习BookB,就要定义一个learnBookB()的方法,并自己来创建BookB的对象。然后我们建立一个测试类Test.java来创建一个Student对象,可以分别调用learnBookA()和learnBookB()方法来分别执行两本书的学习过程。具体实现代码如下:
//学生类
public class Student{
public void learnBookA(){
IBook book = new BookA();
book.learn();
}
public void learnBookB(){
IBook book = new BookB();
book.learn();
}
}
//测试运行
public class Test{
public static void main(){
Student student = new Student();
student.learnBookA();
student.learnBookB();
}
}
该方法在调用者Student需要调用被调用者IBook时,需要由自己创建一个IBook对象。这种做法的缺点是,无法更换被调用者,并且要负责被调用者的整个生命周期。具体形式如下图二所示:

图二:自己创建方式
2)get——工厂模式
一切对象都由自己创建的缺点是,每一次调用都需要自己来负责创建对象,创建的对象会到处分散,造成管理上的麻烦,比如异常处理等。因此,我们可以将对象创建的过程提取出来,由一个工厂(Factory)统一来创建,需要什么对象都可以从工厂中取得。
例如下例中,我们创建了一个工厂类BookFactory,为该类添加两个函数getBookA()和getBookB(),分别用于创建BookA和BookB的对象。然后再创建Student中learnBookA()和learnBookB()中的方法,改为分别在该工厂类中取得这两个对象。具体实现代码如下;
//图书工厂
public class BookFactory{
public static IBook getBookA(){
IBook book = new BookA();
}
public static IBook getBookB(){
IBook book = new BookB();
}
}
//学生类
public class Student{
public void learnBookA(){
IBook book = BookFactory.getBookA();
book.learn();
}
public void learnBookB(){
IBook book = BookFactory.getBookB();
book.learn();
}
}
//测试运行
public class Test{
public static void main(){
Student student = new Student();
student.learnBookA();
student.learnBookB();
}
}
此时与第一种方法的区别是,多了一个工厂类,并将Student中创建对象的代码提取到了工厂类,Student直接从工厂类中取得要创建的对象。这种方法的优点是,实现了对象的统一创建,调用者无须关心对象创建的过程,只管从工厂中取得即可。具体形式如下图三所示:

图三:工厂模式
这种方法实现了一定程度的优化,使得代码的逻辑也更趋向于统一。但是,对象的创建依然不灵活,因为对象的取得完成取决于工厂,又多了中间一道工序。
3)set——外部注入
显然,第一种方式依赖于被调用者对象,第二种方式依赖于工厂,都存在依赖性。为了彻底解决依赖性的问题,我们又取消了工厂类,并仅仅为Student添加一个学习的方法learnBook(),输入的参数是接口类型IBook。在使用Student的方法时,我们先创建IBook的具体对象,然后再把该对象作为learnBook()的输入参数注入到Student,调用接口IBook的统一方法learn()即可完成学习过程。具体实现代码如下所示:
//学生类
public class Student{
public void learnBook(IBook book){
book.learn();
}
}
//测试运行
public class Test{
public static void main(){
IBook bookA = new BookA();
IBook bookB = new BookB();
Student student = new Student();
student.learnBook(bookA);
student.learnBook(bookB);
}
}
这样我们完全简化了Student类的方法,learnBook()的方法不再依赖于某一个特定的Book,而是使用了接口类IBook,这样只要在外部创建任意IBook的实现对象输入到该方法即可,使得Student类完全解脱了与具体某一种Book的依赖关系。上例中的Test.java,分别创建了bookA和bookB对象,同样都可以调用Student的learnBook()方法,使得Student变得完全通用。具体形式如下图四所示:

图四:外部注入方式
可见,set——外部注入方式完全抛开了依赖关系的枷锁,可以自由的由外部注入,这就是IoC,将对象的创建个获取提前到外部,由外部容器提供需要的组件。
控制反转IoC简介的更多相关文章
- 浅析“依赖注入(DI)/控制反转(IOC)”的实现思路
开始学习Spring的时候,对依赖注入(DI)——也叫控制反转(IOC)—— 的理解不是很深刻.随着学习的深入,也逐渐有了自己的认识,在此记录,也希望能帮助其他入门同学更深入地理解Spring.本文不 ...
- 控制反转IOC的依赖注入方式
引言: 项目中遇到关于IOC的一些内容,因为和正常的逻辑代码比较起来,IOC有点反常.因此本文记录IOC的一些基础知识,并附有相应的简单实例,而在实际项目中再复杂的应用也只是在基本应用的基础上扩展而来 ...
- 控制反转IOC与依赖注入DI
理解 IOC http://www.cnblogs.com/zhangchenliang/archive/2013/01/08/2850970.html IOC 相关实例 的http:// ...
- 控制反转(Ioc)和依赖注入(DI)
控制反转IOC, 全称 “Inversion of Control”.依赖注入DI, 全称 “Dependency Injection”. 面向的问题:软件开发中,为了降低模块间.类间的耦合度,提倡基 ...
- 控制反转IOC与依赖注入DI【转】
转自:http://my.oschina.net/1pei/blog/492601 一直对控制反转.依赖注入不太明白,看到这篇文章感觉有点懂了,介绍的很详细. 1. IoC理论的背景我们都知道,在采用 ...
- 依赖注入(DI)和控制反转(IOC)
依赖注入(DI)和控制反转(IOC) 0X1 什么是依赖注入 依赖注入(Dependency Injection),是这样一个过程:某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只 ...
- iOS控制反转(IoC)与依赖注入(DI)的实现
背景 最近接触了一段时间的SpringMVC,对其控制反转(IoC)和依赖注入(DI)印象深刻,此后便一直在思考如何使用OC语言较好的实现这两个功能.Java语言自带的注解特性为IoC和DI带来了极大 ...
- 个人对【依赖倒置(DIP)】、【控制反转(IOC)】、【依赖注入(DI)】浅显理解
一.依赖倒置(Dependency Inversion Principle) 依赖倒置是面向对象设计领域的一种软件设计原则.(其他的设计原则还有:单一职责原则.开放封闭原则.里式替换原则.接口分离原则 ...
- 【转载】浅析依赖倒置(DIP)、控制反转(IOC)和依赖注入(DI)
原文地址 http://blog.csdn.net/briblue/article/details/75093382 写这篇文章的原因是这两天在编写关于 Dagger2 主题的博文时,花了大量的精力来 ...
随机推荐
- JavaScript填坑史
说明: 这是笔者平时积累的一些觉得比较有意思或是比较有难度的JavaScript题目理解和心得,会保持长期更新. 1.setTimeout和setInterval深入理解 在setTimeout和s ...
- Windows Server配置Jenkins,实现监测SVN提交自动构建.net4.5的项目
1,持续集成 概念:http://baike.baidu.com/view/5253255.htm,对于大多数人而言,自动构建/自动测试/自动部署,已经很发挥它的价值了.选择上: 推荐jenkins, ...
- android 网络加载图片,对图片资源进行优化,并且实现内存双缓存 + 磁盘缓存
经常会用到 网络文件 比如查看大图片数据 资源优化的问题,当然用开源的项目 Android-Universal-Image-Loader 或者 ignition 都是个很好的选择. 在这里把原来 ...
- 把NetDimension.NanUI项目从C#6.0语法还原到C#5.0
前言 找Cef资料时看到一个比较好的封装NanUI for Winform发布,让Winform界面设计拥有无限可能,下载代码后发现是Vs2015+C#6.0开发的,本机没有VS2015也不想安装.于 ...
- 领域驱动设计常见问题FAQ
本文出处:http://www.cqrs.nu/Faq What is a domain? The field for which a system is built. Airport managem ...
- 高性能 Socket 组件 HP-Socket v3.2.1 正式发布
HP-Socket 是一套通用的高性能 TCP/UDP Socket 组件,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C ...
- GJM :C#开发 异步处理是目的,多线程是手段
但是BeginAccept和EndAccept不就是system.net.socket封装好的异步socket吗如果用多线程来实现的话那就不叫异步了吧 1.再次强调,异步是目的,多线程是手段. 所谓异 ...
- 推荐15款最佳的 jQuery 分步引导插件
当用户浏览到一个网站,它可能从不知道如何浏览,如何操作网站或 Web 应用程序的内容和流程.在这篇文章中,我们编制了一些最好的 jQuery 引导插件列表.你会发现这些插件对于提高你的网站的整体用户体 ...
- Sublime Text 2 windows8安装插件失败解决
事件是这样的: 1.安装Package Control组件后, 2.调出Install Package选项安装插件,状态栏显示成功, 3.但打开Packages目录也看不到,Sublime插件管理也没 ...
- 天津政府应急系统之GIS一张图(arcgis api for flex)讲解(六)地图搜索模块
config.xml文件的配置如下: <widget label="地图搜索" icon="assets/images/emergency_resource_ove ...