但是,想象一下:在一个相当复杂的应用程序中这种情况屡屡发生,而您还希望能动态地——至少要在外部——改变对象关联。假设有一个DummyProtocolAdapter,它总是返回42这个值,使用它来进行测试。为什么不提供一个单个的统一框架?——让开发人员能够依靠该框架,以一种一致的、外部配置的方式建立类之间的关联,并且不引起工厂单元素类(factory singleton classe)的异常增加。这听起来可能没什么大不了,但它要依赖于IoC的简单性。
我们使用一个TemperatureSensor类,它与一个实现ProtocolAdapterIfc接口的类有关联。TemperatureSensor将使用该委托类来获得温度值。如UML图所示,在实现ProtocolAdapterIfc并且随后可用于该关联的应用程序中有若干个类。我们将使用IoC框架(在本例中是Spring)来声明要使用的ProtocolAdaperIfc的实现。Spring将在运行时建立关联。我们先来看XML代码,它将实例化TemperatureSensor对象并将一个ProtocolAdapterIfc实现与它关联起来。该代码如下所示:
<bean id="tempSensor"
class="yourco.project.sensor.TemperatureSensor">
<property name="sensorDelegate">
<ref bean="sensor"/>
</property>
</bean>
<!-- Sensor to associate with tempSensor -->
<bean id="sensor" class="yourco.project.comm.RS232Adapter"/>
看了这些代码之后,对于其目的就应该非常清楚了。我们配置Spring来实例化TemperatureSensor对象,并将其与RS232Adapter相关联,作为实现ProtocolAdapterIfc接口的类。若想改变已经与TemperatureSensor关联的实现,惟一需要更改的就是sensor bean标记中的class值。只要实现了ProtocolAdapterIfc接口,TemperatureSensor就不再关心关联了什么。
将这应用于应用程序相当简单。我们必须先接入Spring框架,将它指向正确的配置文件,然后根据名称向Spring索取tempSensor对象的实例。下面是相应的代码:
ClassPathXmlApplicationContext appContext =
new ClassPathXmlApplicationContext(
new String[]
{ "simpleSensor.xml" });
BeanFactory bf = (BeanFactory) appContext;
TemperatureSensor ts = (TemperatureSensor)
bf.getBean("tempSensor");
System.out.println("The temp is: "+
ts.getTemperature());
可以看出,这些代码并不是非常难。首先是启动Spring并指定要使用的配置文件。接下来根据名称(tempSensor)引用Bean。Spring使用这样一种机制:基于simpleSensor.xml文件的描述创建该对象并与其他对象关联。它用于注入依赖性——在本例中,通过将它作为一个参数传递给sensorDelegate()方法而实例化RS232Adapter对象并将其与TemperatureSensor对象关联。
比较起来,使用编程式Java完成这一任务也不是很难。如下所示:
TemperatureSensor ts2 = new TemperatureSensor();
ts2.setSensorDelegate(new RS232Adapter());
纯粹主义者或许会认为实际上这是更好的方法。代码行数少,并且可读性可能更强。确实如此,但这种方法的灵活性要小得多。
• 可以随意换入和换出不同层中不同对象的不同实现。例如,若Web层中的组件需要来自新业务对象的额外的功能,您只需将该业务对象与Web层对象相关联,就像上面TemperatureSensor例子中的做法。它将被“注入”到Web对象中以随时使用。
• 能够重新配置整个应用程序的结构,意味着可以轻松更改数据源。比如说,或者为不同的部署场景创建不同的配置文件,或者为测试场景创建更有用的、不同的配置文件。在测试场景中可能会注入实现接口的模拟对象,而不注入真正的对象。稍后我们将介绍一个这样的例子。
上面所述的例子可能是依赖注入的最简单形式。利用相同的策略,我们不仅能够关联不同的类,还能够在类中安装属性。诸如字符串、整数或浮点数之类的属性,只要具有JavaBean样式的存取器,就可以通过Spring配置文件将它们注入类中。我们还可以通过构造函数来创建对象和安装属性或bean引用。其语法只比通过属性进行设置稍稍复杂一些。
所有这一切都是利用一种灵活的声明性配置完成的。无需更改代码,建立依赖关联的所有艰难任务都由Spring来完成。
