控制反转&依赖注入DI
1.(通俗的解释) 2.(专业的解释) IoC(Inversion of Control)是近年来兴起的一种思想,不仅仅是编程思想。主要是协调各组件间相互的依赖关系,同时大大提高了组件的可移植性,组件的重用机会也变得更多。在传统的实现中,由程序内部代码来控制程序之间的关系。我们经常使用new关键字来实现两组键间关系的组合,这种实现的方式会造成组件之间耦合(一个好的设计,不但要实现代码重用,还要将组件间关系解耦)。IoC很好的解决了该问题,它将实现组件间关系从程序内部提到外部容器来管理。也就是说由容器在运行期将组件间的某种依赖关系动态的注入组件中。控制程序间关系的实现交给了外部的容器来完成。即常说的好莱坞原则“Don't call us,we'll call you”。 Ioc也有称为DI(Dependecy Injection 依赖注射),由Martin Fowler的一篇《Inversion ofControl Containers and the Dependency Injection pattern》提出。 从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的一个复杂使用不多的项目) 有过EJB开发经验的人都知道,每个EJB的调用都需要通过JNDI寻找到工厂性质的Home接口,在我的教程EJB是什么章节中,我也是从依赖和工厂模式角度来阐述EJB的使用。 在通常传统情况下,为了实现调用者和被调用者解耦,分离,一般是通过工厂模式实现的,下面将通过比较工厂模式和Ioc模式不同,加深理解Ioc模式。 二、工厂模式和Ioc 假设有两个类B 和 C:B作为调用者,C是被调用者,在B代码中存在对C的调用: public class B{ public class B{ public B(){ } 每次运行时,MyFactory可根据配置文件XML中定义的C子类实现,通过createInstanceOfC()生成C的具体 实例。 public class B{ public class client{ 主要区别体现在B类的代码,如果使用Ioc,在B类代码中将不需要嵌入任何工厂模式等的代码,因为这些工厂模式其实还是与C有些间接的联系,这样,使用Ioc彻底解耦了B和C之间的联系。 使用Ioc带来的代价是:需要在客户端或其它某处进行B和C之间联系的组装。 所以,Ioc并没有消除B和C之间这样的联系,只是转移了这种联系。 Ioc和AOP 通过下列代码说明如何使用Picocontainer实现AOP,该例程主要实现是记录logger功能,通过Picocontainer可以使用简单一行,使所有的应用类的记录功能激活。首先编制一个记录接口: public interface Logging { public void enableLogging(Log log); } imp 一般的普通应用JavaBeans都可以继承这个类,假设PicoUserManager是一个用户管理类,代码如下: public class PicoUserManager extends LogSwitcher ..... //业务功能 ..... //业务功能 DefaultPicoContainer container = new DefaultPicoContainer(); Logging logging = (Logging) container.getComponentMulticaster(); logging.enableLogging(new SimpleLog("pico"));//激活log 由上代码可见,通过使用简单一行logging.enableLogging()方法使所有的应用类的记录功能激活。这是不是类似AOP的advice实现? 总之,使用Ioc模式,可以不管将来具体实现,完全在一个抽象层次进行描述和技术架构,因此,Ioc模式可以为容器、框架之类的软件实现提供了具体的实现手段,属于架构技术中一种重要的模式应用。J道的JdonSD框架也使用了Ioc模式。 参考资料: Inversion of Control Containers and the Dependency Injection pattern 三、IoC的几种实现类型 (1)Type1接口注入 通常做法是利用接口将调用者与实现者分离。 (2)setter方法注入 在类中暴露setter方法来实现依赖关系。 (3)Type3构造子注入 即通过构造方法完成依赖关系。 public class Sport { private InterfaceBall ball; public Sport(InterfaceBall arg) { ball = arg; } } 可以看到,通过类的构造方法建立依赖关系。由于Type3在构造期就形成了对象的依赖关系,即存对象的重用变的困难。有些框架需要组件提供一个默认的构造方法,此时就体现了Type3的局限性。通常所有的参数都是通过构造方法注入的,当对象间的依赖关系较多时,构造方法就显的比较复杂,不利于单元测试。PicoContainer就是实现了Type3依赖注入模式的轻量级容器。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |