控制反转(IOC)模式(又称DI:Dependency Injection)就是Inversion of Control,控制反转。在Java开发中,IoC意味着将你设计好的类交给系统去控制,而不是在你的类内部控制。这称为控制反转。
IoC(Inversion of Control)是近年来兴起的一种思想,不仅仅是编程思想。主要是协调各组件间相互的依赖关系,同时大大提高了组件的可移植性,组件的重用机会也变得更多。在传统的实现中,由程序内部代码来控制程序之间的关系。我们经常使用new关键字来实现两组键间关系的组合,这种实现的方式会造成组件之间耦合(一个好的设计,不但要实现代码重用,还要将组件间关系解耦)。IoC很好的解决了该问题,它将实现组件间关系从程序内部提到外部容器来管理。也就是说由容器在运行期将组件间的某种依赖关系动态的注入组件中。控制程序间关系的实现交给了外部的容器来完成。即常说的好莱坞原则“Don't call us, we'll call you”。
Ioc也有称为DI(Dependecy Injection 依赖注射),由Martin Fowler的一篇《Inversion of Control Containers and the Dependency Injection pattern》提出。
分离关注( Separation of Concerns : SOC)是Ioc模式和AOP产生最原始动力,通过功能分解可得到关注点,这些关注可以是 组件Components, 方面Aspects或服务Services。
从GOF设计模式中,我们已经习惯一种思维编程方式:Interface Driven Design 接口驱动,接口驱动有很多好处,可以提供不同灵活的子类实现,增加代码稳定和健壮性等等,但是接口一定是需要实现的,也就是如下语句迟早要执行:
AInterface a = new AInterfaceImp();
AInterfaceImp是接口AInterface的一个子类,Ioc模式可以延缓接口的实现,根据需要实现,有个比喻:接口如同空的模型套,在必要时,需要向模型套注射石膏,这样才能成为一个模型实体,因此,我们将人为控制接口的实现成为“注射”。
Ioc英文为 Inversion of Control,即反转模式,这里有著名的好莱坞理论:你呆着别动,到时我会找你。
其实Ioc模式也是解决调用者和被调用者之间的一种关系,上述AInterface实现语句表明当前是在调用被调用者AInterfaceImp,由于被调用者名称写入了调用者的代码中,这产生了一个接口实现的原罪:彼此联系,调用者和被调用者有紧密联系,在UML中是用依赖 Dependency 表示。
但是这种依赖在分离关注的思维下是不可忍耐的,必须切割,实现调用者和被调用者解耦,新的Ioc模式 Dependency Injection 模式由此产生了, Dependency Injection模式是依赖注射的意思,也就是将依赖先剥离,然后在适当时候再注射进入。
一、Ioc模式(Dependency Injection模式)有三种:
第一种类型 从JNDI或ServiceManager等获得被调用者,这里类似ServiceLocator模式。 1.EJB/j2ee 2. Avalon(Apache的一个复杂使用不多的项目)
第二种类型 使用JavaBeans的setter方法 1. Spring Framework,2.WebWork/XWork
第三种类型 在构造方法中实现依赖 1. PicoContainer,2. HiveMind
有过EJB开发经验的人都知道,每个EJB的调用都需要通过JNDI寻找到工厂性质的Home接口,在我的教程EJB是什么章节中,我也是从依赖和工厂模式角度来阐述EJB的使用。
在通常传统情况下,为了实现调用者和被调用者解耦,分离,一般是通过工厂模式实现的,下面将通过比较工厂模式和Ioc模式不同,加深理解Ioc模式。
二、工厂模式和Ioc
假设有两个类B 和 C:B作为调用者,C是被调用者,在B代码中存在对C的调用:
java 代码
- public class B{
-
private C comp;
- ......
- }
实现comp实例有两种途径:单态工厂模式和Ioc。
工厂模式实现如下:
java 代码
- public class B{
-
private C comp;
-
private final static MyFactory myFactory = MyFactory.getInstance();
-
-
public B(){
-
this.comp = myFactory.createInstanceOfC();
-
- }
-
public void someMethod(){
-
this.comp.sayHello();
- }
- ......
- }
特点:
每次运行时,MyFactory可根据XML配置文件中定义的C子类实现,通过createInstanceOfC()生成C的具体实例。
使用Ioc依赖性注射( Dependency Injection )实现Picocontainer如下,B类如同通常POJO类,如下:
java 代码
- public class B{
-
private C comp;
-
public B(C comp){
-
this.comp = comp;
- }
-
public void someMethod(){
-
this.comp.sayHello();
- }
- ......
- }
假设C接口/类有有一个具体实现CImp类。当客户端调用B时,使用下列代码:
java 代码
- public class client{
-
public static void main( String[] args ) {
-
DefaultPicoContainer container = new DefaultPicoContainer();
-
container.registerComponentImplementation(CImp.class);
-
container.registerComponentImplementation(B.class);
-
B b = (B) container.getComponentInstance(B.class);
- b.someMethod();
- }
- }
因此,当客户端调用B时,分别使用工厂模式和Ioc有不同的特点和区别:
主要区别体现在B类的代码,如果使用Ioc,在B类代码中将不需要嵌入任何工厂模式等的代码,因为这些工厂模式其实还是与C有些间接的联系,这样,使用Ioc彻底解耦了B和C之间的联系。
使用Ioc带来的代价是:需要在客户端或其它某处进行B和C之间联系的组装。
所以,Ioc并没有消除B和C之间这样的联系,只是转移了这种联系。
这种联系转移实际也是一种分离关注,它的影响巨大,它提供了AOP实现的可能。
Ioc和AOP
AOP我们已经知道是一种面向切面的编程方式,由于Ioc解放自由了B类,而且可以向B类实现注射C类具体实现,如果把B类想像成运行时的横向动作,无疑注入C类子类就是AOP中的一种Advice,如下图:
通过下列代码说明如何使用Picocontainer实现AOP,该例程主要实现是记录logger功能,通过Picocontainer可以使用简单一行,使所有的应用类的记录功能激活。
首先编制一个记录接口:
java 代码
- public interface Logging {
-
-
public void enableLogging(Log log);
-
- }
有一个LogSwitcher类,主要用来激活具体应用中的记录功能:
java 代码
- import org.apache.commons.logging.Log;
- public class LogSwitcher
- {
-
protected Log m_log;
-
public void enableLogging(Log log) {
- m_log = log;
-
m_log.info("Logging Enabled");
- }
- }
一般的普通应用JavaBeans都可以继承这个类,假设PicoUserManager是一个用户管理类,代码如下:
java 代码
- public class PicoUserManager extends LogSwitcher
- {
-
.....
- }
- public class PicoXXXX1Manager extends LogSwitcher
- {
-
-
.....
- }
- public class PicoXXXX2Manager extends LogSwitcher
- {
-
-
.....
- }
注意LogSwitcher中Log实例是由外界赋予的,也就是说即将被外界注射进入,下面看看使用Picocontainer是如何注射Log的具体实例的。
java 代码
- DefaultPicoContainer container = new DefaultPicoContainer();
-
container.registerComponentImplementation(PicoUserManager.class);
-
container.registerComponentImplementation(PicoXXXX1Manager.class);
-
container.registerComponentImplementation(PicoXXXX2Manager.class);
- .....
-
- Logging logging = (Logging) container.getComponentMulticaster();
-
-
logging.enableLogging(new SimpleLog("pico"));
由上代码可见,通过使用简单一行logging.enableLogging()方法使所有的应用类的记录功能激活。这是不是类似AOP的advice实现?
总之,使用Ioc模式,可以不管将来具体实现,完全在一个抽象层次进行描述和技术架构,因此,Ioc模式可以为容器、框架之类的软件实现提供了具体的实现手段,属于架构技术中一种重要的模式应用。J道的JdonSD框架也使用了Ioc模式。
参考资料:
Inversion of Control Containers and the Dependency Injection pattern
A Brief Introduction to IoC
Ioc容器的革命性优点
Java企业系统架构选择考量
IOC模式的思考和疑问
三、IoC的几种实现类型
(1)Type1接口注入
通常做法是利用接口将调用者与实现者分离。
java 代码
- public class Sport {
- private InterfaceBall ball;
- public void init() {
-
-
ball = (InterfaceBall) Class.forName("Basketball").newInstance();
- }
- }
Sport类在编译期依赖于InterfaceBall的实现,为了将调用者与实现者分离,我们动态生成Basketball类并通了强制类型转换为InterfaceBall。Apache Avalon是一个典型的Type1型IoC容器。
(2)setter方法注入
在类中暴露setter方法来实现依赖关系。
java 代码
- public class Sport {
- private InterfaceBall ball;
- public void setBall(InterfaceBall arg) {
- ball = arg;
- }
- }
这种方式对已经习惯了JavaBean的程序员而言,更显直观。Spring就是实现了该类型的轻量级容器。
(3)Type3构造子注入
即通过构造方法完成依赖关系。
java 代码
- public class Sport {
- private InterfaceBall ball;
- public Sport(InterfaceBall arg) {
- ball = arg;
- }
- }
可以看到,通过类的构造方法建立依赖关系。由于Type3在构造期就形成了对象的依赖关系,即存对象的重用变的困难。有些框架需要组件提供一个默认的构造方法,此时就体现了Type3的局限性。通常所有的参数都是通过构造方法注入的,当对象间的依赖关系较多时,构造方法就显的比较复杂,不利于单元测试。PicoContainer就是实现了Type3依赖注入模式的轻量级容器。
原文出自:http://seed.iteye.com/blog/65346
分享到:
相关推荐
### Spring IOC控制反转详解 #### 一、Spring框架简介 Spring框架是一个开源的Java平台,提供了全面的基础架构支持,让开发者能够轻松地开发出松耦合的应用程序。它通过依赖注入(Dependency Injection, DI)和...
spring IOC控制反转 spring IOC控制反转 spring IOC控制反转
**Spring技术--IOC控制反转** 在Java开发领域,Spring框架以其强大的功能和广泛的应用而闻名。其中,IOC(Inversion of Control,控制反转)是Spring的核心特性之一,它改变了传统对象创建和管理的方式,实现了依赖...
### IOC控制反转在代码中的体现 #### 一、IOC(Inversion of Control)概念解析 IOC,即控制反转,是一种设计思想,在Java开发领域中,它主要被用来消除程序之间的依赖性,使得类的设计更加灵活。传统的编程模式下...
IOC控制反转代码,bilibili配套文件 IOC(Inversion of Control,控制反转)是 Spring 框架的核心机制之一,它是一个用于创建和管理对象的容器。控制反转是将对象的创建进行反转,常规情况下,对象都是开发者手动...
### IOC控制反转学习文档 #### 一、控制反转(IOC)概述 控制反转(Inversion of Control,简称IOC),是Spring框架的核心概念之一。它通过管理对象间的依赖关系,实现了对象的解耦,使得代码更加灵活且易于维护。在...
【Spring框架IoC控制反转】 一、Spring框架是什么 Spring框架是Java开发中的一款轻量级框架,诞生于2003年,旨在简化企业级应用的开发复杂性。Spring的核心理念包括控制反转(IoC)和面向切面编程(AOP)。作为一...
### Spring框架中的IoC控制反转详解 #### 一、IoC概述 控制反转(Inversion of Control,简称IoC)是一种设计思想,在Spring框架中,它主要用来解决对象依赖问题。传统的面向对象编程中,对象之间的依赖关系由对象...
**Spring IOC控制反转详解** 在Java开发中,Spring框架的核心特性之一就是IOC(Inversion of Control,控制反转),它改变了传统程序设计中的对象依赖管理方式,使得开发者可以更专注于业务逻辑,而不是对象的创建...
基础与环境搭建 Bean使用详解 IOC控制反转 AOP切面编程 事务管理机制 MVC开发模式
"IoC(控制反转)"是软件设计模式中的一个重要概念,它在现代软件开发,特别是.NET框架下的C#编程中占据了核心地位。控制反转的主要思想是将对象之间的依赖关系从代码内部转移到外部容器,从而使代码更加灵活、可...
【IOC 控制反转】Android 视图依赖注入 ( 视图依赖注入步骤 | 视图依赖注入代码示例 ) https://hanshuliang.blog.csdn.net/article/details/120404805 博客源码快照
【IOC 控制反转】Android 布局依赖注入 ( 布局依赖注入步骤 | 布局依赖注入代码示例 ) https://hanshuliang.blog.csdn.net/article/details/120402953 博客源码快照
Spring框架的核心特性之一就是依赖注入(Dependency Injection,简称DI),它通过控制反转(Inversion of Control,简称IOC)实现。这个"helloIoc.zip"压缩包包含的是一组用于演示Spring IOC基本概念和使用的测试...
IOC(Inversion of Control,控制反转)是一种设计原则,它改变了传统程序设计中对象之间的依赖关系。在没有IOC的情况下,一个对象通常会自行创建或查找它需要协作的对象,这导致了对象间的紧密耦合。然而,IOC通过...
控制反转(IOC,Inversion of Control)是一种设计模式,它在软件工程中被广泛应用,特别是在Java开发中。IoC的核心思想是将对象的创建和管理权交给一个外部容器,而不是让对象自行创建和管理依赖。这有助于降低耦合...
Spring IOC(Inversion of Control,控制反转)是Spring框架的核心特性,它改变了传统Java应用程序中对象的创建和管理方式。在传统的程序设计中,我们通常手动创建对象并管理它们之间的依赖关系,而在Spring中,这些...
在本案例中,我们将探讨如何使用Autofac来实现数据库操作的控制反转。 首先,了解Autofac的基本概念。Autofac是一个轻量级的DI库,它允许开发者在运行时动态地组合应用程序组件。通过注册服务(接口或抽象类)和...
在软件开发领域,IOC(Inversion of Control,控制反转)和DI(Dependency Injection,依赖注入)是两种重要的设计模式,特别是在Java和Spring框架中被广泛使用。这些概念有助于提高代码的可测试性、可维护性和模块...