控制反转(IoC) 的理解
2012-08-16 17:56
232 查看
控制反转是一个常见的面向对象技术,它主要应用在框架中。如 GUI框架,Spring框架等,这些框架为设计特定的应用程序提供了一般性的步骤,框架把核心的控制流程集成于自身,仅仅把一些具体的实现任务交给用户(程序员即为框架的用户),正是由于这些框架的产生才有必要用到控制反转技术。 也就是说,如果GUI框架仅仅被一个人使用,那么完全不用控制反转也行,因为此框架仅为一个人使用,这个人使用的类是什么样子的,有什么样的类,这个人心里很明白,它可以把这些类写死在代码中。 但这个框架如果被许多人使用,就需要考虑控制反转问题了。看例子:
下面例子的作用是:提供一个导演的名子给 moviesDirectedBy 方法,它就能返回此导演所导演过的所有电影。
现在的问题是 finder 是个什么东西,它是如何实现的?如下代码所示:
finder 可以看成是一个接口即MovieFinder,在 MovieLister类的构造函数中对它进行了实例化,即
ColonDelimitedMovieFinder类从一个以冒号分隔的 文本文件中读取电影列表。
从现在来看,上面的实现都算顺利,没有发现不托之处,现在问题来了:
我的一个朋友想使用我的代码,即想使用我的 MovieLister 类, 我的MovieLister类现在有了"框架"的味道了。但朋友的 MovieFinder如何实现我可不确定,它也许把电影列表存储在XML文件中或者直接从网上请求的,那么MovieLister如何去实例化 MovieFinder呢,没有办法直接实现。现在类的关系如下图:
MovieLister需要实例化一个 MovieFinderImpl 来找出所有的电影列表,而现在这个 MovieFindImpl 是个什么样子的根本不确定,那么这个问题如何解决。
解决办法如下图所示:
引入一个 Assembler 的装配类,由这个类来告诉 MovieLister MovieFinderImpl具体是什么,这个装配过程在运行时通过Java反射机制来完成,这个装配的过程也就是Dependency Injection(依赖注入), 依赖注入有三种方式,分别为:
1 通过构造函数依赖注入
2 通过配置文件依赖注入
3 通过接口依赖注入
在这里只讨论第2种情况:通过配置文件依赖注入(这也是Spring 框架常用的方式)
配置文件就是指 上上图的 XML文件,在配置文件中声明了 MovieLister,同时也定义了 MovieLister 所关联的 MovieFinder;配置文件中也声明了 MovieFinder,这个MovieFinder 标签指明了一个 MovieFinderImpl即 ColonMovieFinder,整个 MovieLister框在运行时会动态的加载 XML 文件,并从中提取出 MovieLister和MovieFinder 的相关信息,并用反射机制实例化了具体的 MovieFinderImpl。
在这里有个重点:
MovieLister类的编写必须按照一定的格式,框架才能为其“注入”适当的类,这个格式就是:
即类的编写必须写一个 private MovieFinder finder 并写一个 setFinder 的方法(名子必须是这样)。
其它方面的思考:
本文研究的初衷不是针对 Spring,而是针对 Android, Android的UI设计主要采用 XML 的方式,其实这也是“依赖注入”的形式。可以想一想程序中的每一个 Activity,Service等组件都是要在 manifest.xml中声明的,不然程序就会出错。也就是Android框架把你 XML 文件中的 Activity等注入到 Android的 framework 中,这样系统就能正常运行起来了。注入 Android 框架中的 Activity 必须从 android.app.Activity
继承,而且还要实现 onCreate/onResume/onPause 等方法,这就相当于 MovieFinder 的具体类必须实现 MovieFinder接口一样,这是框架内部需要调用的方法。
关于 Android总结为一句话帮助自己记忆:
manifest.xml配置了Activity,框架读取xml并把注册的Activity注入到框架中,并调用规定好的 Activity 的生命周期方法进行动作。
本文参考:http://www.martinfowler.com/articles/injection.html 有关“依赖注入”的介绍,需要更多了解可以点击此链接
下面例子的作用是:提供一个导演的名子给 moviesDirectedBy 方法,它就能返回此导演所导演过的所有电影。
class MovieLister... public Movie[] moviesDirectedBy(String arg) { List allMovies = finder.findAll(); for (Iterator it = allMovies.iterator(); it.hasNext();) { Movie movie = (Movie) it.next(); if (!movie.getDirector().equals(arg)) it.remove(); } return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]); }
现在的问题是 finder 是个什么东西,它是如何实现的?如下代码所示:
public interface MovieFinder { List findAll(); }
class MovieLister... private MovieFinder finder; public MovieLister() { finder = new ColonDelimitedMovieFinder("movies1.txt"); }
finder 可以看成是一个接口即MovieFinder,在 MovieLister类的构造函数中对它进行了实例化,即
finder = new ColonDelimitedMovieFinder("movies1.txt");
ColonDelimitedMovieFinder类从一个以冒号分隔的 文本文件中读取电影列表。
从现在来看,上面的实现都算顺利,没有发现不托之处,现在问题来了:
我的一个朋友想使用我的代码,即想使用我的 MovieLister 类, 我的MovieLister类现在有了"框架"的味道了。但朋友的 MovieFinder如何实现我可不确定,它也许把电影列表存储在XML文件中或者直接从网上请求的,那么MovieLister如何去实例化 MovieFinder呢,没有办法直接实现。现在类的关系如下图:
MovieLister需要实例化一个 MovieFinderImpl 来找出所有的电影列表,而现在这个 MovieFindImpl 是个什么样子的根本不确定,那么这个问题如何解决。
解决办法如下图所示:
引入一个 Assembler 的装配类,由这个类来告诉 MovieLister MovieFinderImpl具体是什么,这个装配过程在运行时通过Java反射机制来完成,这个装配的过程也就是Dependency Injection(依赖注入), 依赖注入有三种方式,分别为:
1 通过构造函数依赖注入
2 通过配置文件依赖注入
3 通过接口依赖注入
在这里只讨论第2种情况:通过配置文件依赖注入(这也是Spring 框架常用的方式)
class MovieLister... private MovieFinder finder; public void setFinder(MovieFinder finder) { this.finder = finder; }
class ColonMovieFinder... public void setFilename(String filename) { this.filename = filename; }
<beans> <bean id="MovieLister" class="spring.MovieLister"> <property name="finder"> <ref local="MovieFinder"/> </property> </bean> <bean id="MovieFinder" class="spring.ColonMovieFinder"> <property name="filename"> <value>movies1.txt</value> </property> </bean> </beans>
public void testWithSpring() throws Exception { ApplicationContext ctx = new FileSystemXmlApplicationContext("spring.xml"); MovieLister lister = (MovieLister) ctx.getBean("MovieLister"); Movie[] movies = lister.moviesDirectedBy("Sergio Leone"); assertEquals("Once Upon a Time in the West", movies[0].getTitle()); }
配置文件就是指 上上图的 XML文件,在配置文件中声明了 MovieLister,同时也定义了 MovieLister 所关联的 MovieFinder;配置文件中也声明了 MovieFinder,这个MovieFinder 标签指明了一个 MovieFinderImpl即 ColonMovieFinder,整个 MovieLister框在运行时会动态的加载 XML 文件,并从中提取出 MovieLister和MovieFinder 的相关信息,并用反射机制实例化了具体的 MovieFinderImpl。
在这里有个重点:
MovieLister类的编写必须按照一定的格式,框架才能为其“注入”适当的类,这个格式就是:
class MovieLister... private MovieFinder finder; public void setFinder(MovieFinder finder) { this.finder = finder; }
即类的编写必须写一个 private MovieFinder finder 并写一个 setFinder 的方法(名子必须是这样)。
其它方面的思考:
本文研究的初衷不是针对 Spring,而是针对 Android, Android的UI设计主要采用 XML 的方式,其实这也是“依赖注入”的形式。可以想一想程序中的每一个 Activity,Service等组件都是要在 manifest.xml中声明的,不然程序就会出错。也就是Android框架把你 XML 文件中的 Activity等注入到 Android的 framework 中,这样系统就能正常运行起来了。注入 Android 框架中的 Activity 必须从 android.app.Activity
继承,而且还要实现 onCreate/onResume/onPause 等方法,这就相当于 MovieFinder 的具体类必须实现 MovieFinder接口一样,这是框架内部需要调用的方法。
关于 Android总结为一句话帮助自己记忆:
manifest.xml配置了Activity,框架读取xml并把注册的Activity注入到框架中,并调用规定好的 Activity 的生命周期方法进行动作。
本文参考:http://www.martinfowler.com/articles/injection.html 有关“依赖注入”的介绍,需要更多了解可以点击此链接
相关文章推荐
- Spring IOC(依赖注入、控制反转)概念理解
- Spring IOC(依赖注入、控制反转)概念理解
- 控制反转(IOC)的理解
- 控制反转(IOC) 和依赖注入(DI) 的理解
- 理解依赖注入(IOC)和学习Unity
- 理解PHP 依赖注入|Laravel IoC容器
- 对Spring的IoC和AOP的理解
- IoC和DI的理解
- 看《墨攻》理解IoC概念
- 对IOC容器的理解
- 深入理解IOC控制反转及应用实例
- 看《墨攻》理解IoC概念(二 )http://www.qqread.com/erp/3/j380307_3.html
- 深入理解DIP、IoC、DI以及IoC容器
- Spring:IOC与AOP的个人理解
- 谈谈对Spring IOC的理解
- 关于Spring 的IOC 和 DI 的理解
- Spring(二):IOC和DI的理解
- Spring面试,IoC和AOP的理解
- Spring4深入理解IOC&DI02----Bean配置--自动装配、bean之间的继承与依赖、使用外部属性文件
- Spring面试,IoC和AOP的理解