我正在尝试更改一些遗留代码,以便在Spring框架中使用DI。我有一个具体案例,我想知道哪种方法最适合实施它。
这是一个java桌面应用程序。 DataManager接口用于查询/更改数据存储中的数据。目前只有一个实现使用XML文件进行存储,但将来可以添加SQL实现。对于单元测试,我可能需要模拟它。
目前,需要数据管理器的每一段代码都通过使用工厂来检索它。这是工厂的源代码:
public class DataManagerFactory
{
private static DataManagerIfc dataManager;
public static DataManagerIfc getInstance()
{
// Let assume synchronization is not needed
if(dataManager == null)
dataManager = new XMLFileDataManager();
return dataManager;
}
}
现在我看到有3种方法可以将应用程序更改为使用DI和Spring。
予。仅在工厂中注入依赖项,不要更改任何其他代码。
这是新代码:
public class DataManagerFactory
{
private DataManagerIfc dataManager;
public DataManagerFactory(DataManagerIfc dataManager)
{
this.dataManager = dataManager;
}
public DataManagerIfc getDataManager()
{
return dataManager;
}
public static DataManagerIfc getInstance()
{
return getFactoryInstance().getDataManager();
}
public static DataManagerFactory getFactoryInstance()
{
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"com/mypackage/SpringConfig.xml"});
return context.getBean(DataManagerFactory.class);
}
}
带有bean描述的XML:
<bean id="dataManagerFactory"
class="com.mypackage.DataManagerFactory">
<constructor-arg ref="xmlFileDataManager"/>
</bean>
<bean id="xmlFileDataManager"
class="com.mypackage.datamanagers.xmlfiledatamanager.XMLFileDataManager">
</bean>
II。更改使用数据管理器的每个类,以便它通过构造函数并将其存储为类变量。仅为创建链开始的“根”类创建Spring bean定义。
III。与II相同。但对于使用数据管理器的每个类,都要创建一个Spring bean定义,并使用Spring Ioc容器实例化每个这样的类。
由于我是DI概念的新手,我将非常感谢您提出的正确和“最佳实践”解决方案。 非常感谢提前。
答案 0 :(得分:2)
使用选项3。
第一个选项使您的代码不可测试。您将无法轻松模拟静态工厂方法,以便返回模拟DataManager。
第二个选项将强制您让根类知道所有非根类的所有依赖关系,以使代码可测试。
第三个选项确实使用依赖注入,其中每个bean只知道它的直接依赖关系,并由DI容器注入。
答案 1 :(得分:0)
嗯......你为什么一开始就写这个工厂? Spring并不是为了让你改变你编写代码的方式(不仅仅是为了适应Spring),所以保持工厂是正确的,因为它使用了众所周知的模式。将依赖注入工厂将保留该行为。
答案 2 :(得分:0)
选项3是正确的路线。通过使用这样的配置,您可以有用地获取配置的组件并在 new 配置中使用它们,一切都将按预期工作。
根据经验,我希望一次调用Spring来实例化应用程序上下文并获得顶级bean。我不希望重复调用Spring框架来获取多个bean。所有事情都应该以正确的水平注入,以反映责任等。
小心(因为你是新手),你不会在数据管理器中探索每个可用的课程!这是一个非常常见的错误,如果你没有充分地抽象出集中的职责,你会发现你正在配置有很多经理的课程。当你看到你正在这样做时,现在是退一步看看你的抽象和组件化的好时机。