Knu*_*daa 39 java spring dependency-injection
这可能是一个天真的问题.我目前正在学习Spring框架和依赖注入.虽然DI的基本原理很容易掌握,但是为什么需要一个精心设计的框架来实现它并不是很明显.
考虑以下:
public abstract class Saw
{
public abstract void cut(String wood);
}
public class HandSaw extends Saw
{
public void cut(String wood)
{
// chop it up
}
}
public class ChainSaw extends Saw
{
public void cut(String wood)
{
// chop it a lot faster
}
}
public class SawMill
{
private Saw saw;
public void setSaw(Saw saw)
{
this.saw = saw;
}
public void run(String wood)
{
saw.cut("some wood");
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以简单地做:
Saw saw = new HandSaw();
SawMill sawMill = new SawMill();
sawMill.setSaw(saw);
sawMill.run();
Run Code Online (Sandbox Code Playgroud)
这相当于:
<bean id="saw" class="HandSaw"/>
<bean id="sawMill" class="SawMill">
<property name="saw" ref="saw"/>
</bean>
Run Code Online (Sandbox Code Playgroud)
加:
ApplicationContext context = new ClassPathXmlApplicationContext("sawmill.xml");
SawMill springSawMill = (SawMill)context.getBean("sawMill");
springSawMill.run();
Run Code Online (Sandbox Code Playgroud)
当然,这是一个受到尊重的例子,对于更复杂的对象关系,存储XML文件可能比以编程方式编写文件更有效,但肯定必须有更多的东西呢?
(我知道Spring框架不止于此,但我正在考虑需要一个DI容器.)
在第一个例子中,在中途改变依赖关系也是微不足道的:
// gotta chop it faster
saw = new ChainSaw();
sawMill.setSaw(saw);
sawMill.run();
Run Code Online (Sandbox Code Playgroud)
Ran*_*ron 15
我有完全相同的问题,并且答案是这样的:
当然,你可以做你所描述的"然后你可以简单地做:......"(让我们称之为"A级").但是,这会将A类与HandSaw或SawMill类所需的所有依赖关系联系起来.为什么A应该与HandSaw耦合 - 或者,如果你采取更现实的方案,为什么我的业务逻辑应该耦合到DAO层所需的JDBC连接实现?
我之后提出的解决方案是"然后将依赖项更进一步" - 好吧,所以现在我已将我的视图耦合到JDBC连接,我应该只处理HTML(或Swing,选择你的风格).
由XML(或JavaConfig)配置的DI框架通过让您"获得所需的服务"来解决这个问题.你不关心它是如何初始化的,它需要什么工作 - 你只需获得服务对象并激活它.
此外,你对"加号:"(你所做的SawMill springSawMill = (SawMill)context.getBean("sawMill"); springSawMill.run();)有一个误解- 你不需要从上下文中获取sawMill bean - 应该将sawMill bean注入到你的对象(A类)中DI框架.所以不是...... getBean(...),而是去"sawMill.run()",而不是关心它来自哪里,谁初始化它以及如何.对于你所关心的一切,它可以直接进入/ dev/null,或测试输出,或真正的CnC引擎......关键是 - 你不在乎.所有你关心的都是你的小A级应该按照合同要求做的 - 激活锯木厂.
duf*_*ymo 12
Spring有三个同样重要的功能:
我同意,当你将它与一次调用new相比较时,很难看到依赖注入的优势.在这种情况下,后者肯定会看起来更简单,因为它只是一行代码.Spring的配置总是会增加代码行,所以它不是一个成功的论据.
当你可以从类中进行交叉关注并使用方面以声明方式设置它们时,它开始看起来好多了.与单个"新"调用的比较并不是Spring创建的.
也许使用Spring的最佳结果是它推荐的习惯用法使用接口,分层和DRY这样的好原则.这真的只是Rod Johnson在他的咨询演出中使用的面向对象最佳实践的升华.他发现随着时间的推移,他建立的代码帮助他为客户提供更好的软件.他总结了他在"Expert 1:1 J2EE"中的经验,最终将代码公开为Spring.
我想说,在你认为他的经验可以帮助你编写更好的代码的程度上买入框架.
在你将所有这三个功能结合起来之前,我认为你无法获得Spring的全部价值.
当然,这是一个受到尊重的例子,对于更复杂的对象关系,存储XML文件可能比以编程方式编写文件更有效,但肯定必须有更多的东西呢?
我认为将"接线"放在配置文件中而不是在代码中手动执行更有意义,原因如下:
sawmill使用不同的实例Saw)可以简单地对外部(XML)文件进行更改,不需要更改代码,重新编译,重新部署等.Controller类,它获取一个Service包含你的业务逻辑的类,它使用a DAO来Saw从数据库中获取s,并将其DataSource注入其中,等等. ),手动连接协作者是繁琐的,需要几十行代码,除了连接之外什么都不做.我通常不关心XML或基于DI的DI,因为在我的用例中,它增加了不必要的复杂性.相反,我通常会选择某种形式的手动DI,对我来说,这似乎更自然,并且具有大部分好处.
public class SawDI{
public Saw CreateSaw(){
return new HandSaw();
}
public SawMill CreateSawMill(){
SawMill mill = new SawMill();
mill.SetSaw(CreateSaw());
return mill;
}
}
// later on
SawDI di = new SawDI();
SawMill mill = di.CreateSawMill();
Run Code Online (Sandbox Code Playgroud)
这意味着我仍然集中了耦合并具有其所有优点,而不依赖于更复杂的DI框架或XML配置文件.
如果对插入的类进行硬编码,则需要该类在编译时可用。使用配置文件,您可以在运行时更改使用的锯(在您的情况下),而无需重新编译,甚至可以使用从刚刚放置在类路径中的新 jar 中获取的锯。如果值得,额外的复杂性取决于您必须解决的任务。