控制反转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 主题的博文时,花了大量的精力来 ...
随机推荐
- jsp原理
在eclipse里jsp编译后的java和class文件的位置 eclipse版本不一样,位置也不一样第一种:1.java类编译后产生的.class文件在D:\workspace\test\WEB-I ...
- javascript处理HTML的Encode(转码)和Decode(解码)总结
HTML的Encode(转码)和解码(Decode)在平时的开发中也是经常要处理的,在这里总结了使用javascript处理HTML的Encode(转码)和解码(Decode)的常用方式 一.用浏览器 ...
- Solr3.6.1 在Tomcat6下的环境搭建
Solr3.6.1 在Tomcat6下的环境搭建 Tomcat路径:D:\prg\apache-tomcat-6-solr 简写为tomcat_home Solr文件下载保存路径为:F:\softwa ...
- wpf模仿QQ表情
效果图: style: <Style x:Key="LBXITEM_VERTICAL" TargetType="ListBoxItem"> < ...
- 比较牛X的互联网公司都有哪些作死的行为
以下为近乎家的小近吐血整理: 1流氓行为 臭表碾说的就是你们! 百度 还有这种伪造网页弹窗: 360 不经同意,也不弹窗提醒,直接给我们安装推广软件.比较典型的是 腾讯 腾讯一直走在行业最前端,买 ...
- 速战速决 (6) - PHP: 获取 http 请求数据, 获取 get 数据 和 post 数据, json 字符串与对象之间的相互转换
[源码下载] 速战速决 (6) - PHP: 获取 http 请求数据, 获取 get 数据 和 post 数据, json 字符串与对象之间的相互转换 作者:webabcd 介绍速战速决 之 PHP ...
- 企业管理咨询Interview Checklist
企业管理咨询Interview Checklist 一. 企业战略 1. 您对公司所处行业的看法如何? 2. 请您介绍一下公司的发展历程,主要业务开展状况及核心竞争力.关键成功因素有哪些? 3. 在您 ...
- ABP使用及框架解析系列 - [Unit of Work part.1-概念及使用]
前言 ABP ABP是“ASP.NET Boilerplate Project”的简称. ABP的官方网站:http://www.aspnetboilerplate.com ABP在Github上的开 ...
- 使用git error: RPC failed; result=22, HTTP code = 411
使用git提交比较大的文件的时候可能会出现这个错误 error: RPC failed; result=22, HTTP code = 411 fatal: The remote end hung u ...
- 转:什么是即时编译(JIT)!?OpenJDK HotSpot VM剖析
重点 应用程序可以选择一个适当的即时编译器来进行接近机器级的性能优化. 分层编译由五层编译构成. 分层编译提供了极好的启动性能,并指导编译的下一层编译器提供高性能优化. 提供即时编译相关诊断信息的JV ...