韩国男宝宝名字:入门03 - 依赖注入DI

来源:百度文库 编辑:九乡新闻网 时间:2024/07/15 00:32:40
Added by 良葛格 , last edited by koji on Oct 09, 2007 ( view change )Labels:
(None)

IoC模式基本上是一个高层的概念,在Martin Fowler的Inversion of Control Containers and the Dependency Injection pattern中谈到,实现IoC有两种方式:Dependency Injection与Service Locator。您可以在下面的网址中找到该篇文章:http://www.martinfowler.com/articles/injection.html

Spring所采用的是Dependency Injection来实现IoC,中文翻译为依赖注入,依赖注入的意义是:「保留抽象介面,让组件依赖于抽象介面,当组件要与其它实际的物件发生依赖关系时,借过抽象介面来注入依赖的实际物件。」
看看下面这个程式:
public class BusinessObject { private FloppyWriter writer = new FloppyWriter(); .... public void save() { ... writer.saveToFloppy(); }}
BusinessObject依赖于实际的FloppyWriter,为了让BusinessObject获得重用性,我们不让BusinessObject依赖于实际的FloppyWriter,而是依赖于抽象的介面:
public interface IDeviceWriter { public void saveToDevice();}public class BusinessObject { private IDeviceWriter writer; public void setDeviceWriter(IDeviceWriter writer) { this .writer = writer; } public void save() { .... writer.saveToDevice(); }}public class FloppyWriter implement IDeviceWriter { public void saveToDevice() { .... //实际储存至Floppy的程式码 }}public class UsbDiskWriter implement IDeviceWriter { public void saveToDevice() { .... //实际储存至UsbDisk的程式码 }}
如果今天BusinessObject想要与UseDiskWriter物件发生依赖关系,可以这么建立:
businessObject.setDeviceWriter( new UsbDiskWriter());
由于BusinessObject依赖于抽象介面,在需要建立依赖关系时,我们可以透过抽象介面注入依赖的实际物件。
依赖注入在Martin Fowler的文章中谈到了三种实现方式:interface injection、setter injection与constructor injection。并分别称其为type 1 IoC、type 2 IoC与type 3 IoC。
上面的BusinessObject所实现的是type 2 IoC,透过setter注入依赖关系,而type 3 IoC,则在是建构函式上注入依赖关系,例如:
public class BusinessObject { private IDeviceWriter writer; public BusinessObject(IDeviceWriter writer) { this .writer = writer; } public void save() { .... writer.saveToDevice(); }}
Spring鼓励的是setter injection,但也允许您使用constructor injection,使用setter或constructor来注入依赖关系视您的需求而定,使用constructor的好处之一是,您可以在建构物件的同时一并完成依赖关系的建立,然而如果要建立的物件关系很多,则会在建构函式上留下一长串的参数,这时使用setter会是个不错的选择,另一方面, setter可以有明确的名称可以了解注入的物件会是什么,像是setXXX()这样的名称会比记忆constructor上某个参数位置代表某个物件来得好。
Type 1 IoC是interface injection,使用type 1 IoC时会要求实作介面,这个介面是为容器所用的,容器知道介面上所规定的方法,它可以呼叫实作介面的物件来完成依赖关系的注入,例如:
public interface IDependencyInjection { public void createDependency(Map dependObjects);}public class BusinessObject implement IDependencyInjection { private Map dependObjects; public void createDependency(Map dependObjects) { this .dependObject = dependObjects; //在这边实现与BusinessObject的依赖关系 ...... } public void save() { .... writer.saveToDevice(); }}
如果要完成依赖关系注入的物件,必须实现IDependencyInjection介面,并交由容器管理,容器会呼叫被管理物件的createDependency()方法来完成依赖关系的建立。
在上面的例子中,type 1 IoC要求BusinessObject实现特定的介面,这就使得BusinessObject依赖于容器,如果日后BusinessObject要脱离目前这个容器,就必须修改程式,想想在更复杂的依赖关系中产生更多复杂的介面,组件与容器(框架)的依赖会更加复杂,最后使得组件无法从容器中脱离。
所以type 1 IoC具有强的侵入性,使用它来实现依赖注入会使得组件相依于容器(框架),降低组件的重用性。
Spring的核心是个IoC容器,您可以用setter或constructor的方式来实现您的业务物件,至于物件与物件之间的关系建立,则透过组态设定,让Spring在执行时期根据组态档的设定来为您建立物件之间的依赖关系,您不必特地撰写一些Helper来自行建立这些物件之间的依赖关系,这不仅减少了大量的程式撰写,也降低了物件之间的耦合程度。