当前位置:  开发笔记 > 编程语言 > 正文

了解DI框架的必要性

如何解决《了解DI框架的必要性》经验,为你挑选了5个好方法。

这可能是一个天真的问题.我目前正在学习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");
    }
}

然后你可以简单地做:

Saw saw = new HandSaw();
SawMill sawMill = new SawMill();
sawMill.setSaw(saw);
sawMill.run();

这相当于:




   

加:

ApplicationContext context = new ClassPathXmlApplicationContext("sawmill.xml");
SawMill springSawMill = (SawMill)context.getBean("sawMill");
springSawMill.run();

当然,这是一个受到尊重的例子,对于更复杂的对象关系,存储XML文件可能比以编程方式编写文件更有效,但肯定必须有更多的东西呢?

(我知道Spring框架不止于此,但我正在考虑需要一个DI容器.)

在第一个例子中,在中途改变依赖关系也是微不足道的:

// gotta chop it faster
saw = new ChainSaw();
sawMill.setSaw(saw);
sawMill.run();

Ran Biron.. 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级应该按照合同要求做的 - 激活锯木厂.



1> Ran Biron..:

我有完全相同的问题,并且答案是这样的:
当然,你可以做你所描述的"然后你可以简单地做:......"(让我们称之为"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级应该按照合同要求做的 - 激活锯木厂.


只有在您开始测试之前才有效.然后你希望你有办法将"TestSawImpl"(只是断言)放入A而不是真正的"HandSaw",它需要一堆木头,一个电源和一个经过认证的锯操作员(可能还有一个医生待命) .
不,这总是如此.我可以使用模拟工具轻松编写单元测试.没有必要创建一个`TestSawImpl`,因为模拟工具允许我用一行代码模拟任何`Saw`实现类,即使在编译时不知道具体类.
根据我的理解,这个答案与依赖注入模式的"官方"定义(http://martinfowler.com/articles/injection.html)相矛盾.如果需要在运行时选择实现"Saw"抽象的实际类,则将类"A"耦合到类"HandSaw"是一个问题.否则,在客户端代码中直接实例化Saw实现类是完全可以的.在实际需要的情况下,DI实际上是"将配置与使用分离",而不是默认情况下.

2> Apocalisp..:

依赖注入是隐式参数传递的简并形式,其目的基本相同,以解决所谓的配置问题:

配置问题是在整个程序中传播运行时首选项,允许多个并发配置集在静态保证分离下安全共存.

依赖注入框架弥补了隐含参数的缺乏,Curried函数以及语言中monad的便利设施.



3> duffymo..:

Spring有三个同样重要的功能:

    依赖注入

    面向方面的编程

    框架类库,用于帮助持久化,远程处理,Web mvc等.

我同意,当你将它与一次调用new相比较时,很难看到依赖注入的优势.在这种情况下,后者肯定会看起来更简单,因为它只是一行代码.Spring的配置总是会增加代码行,所以它不是一个成功的论据.

当你可以从类中进行交叉关注并使用方面以声明方式设置它们时,它开始看起来好多了.与单个"新"调用的比较并不是Spring创建的.

也许使用Spring的最佳结果是它推荐的习惯用法使用接口,分层和DRY这样的好原则.这真的只是Rod Johnson在他的咨询演出中使用的面向对象最佳实践的升华.他发现随着时间的推移,他建立的代码帮助他为客户提供更好的软件.他总结了他在"Expert 1:1 J2EE"中的经验,最终将代码公开为Spring.

我想说,在你认为他的经验可以帮助你编写更好的代码的程度上买入框架.

在你将所有这三个功能结合起来之前,我认为你无法获得Spring的全部价值.



4> matt b..:

当然,这是一个受到尊重的例子,对于更复杂的对象关系,存储XML文件可能比以编程方式编写文件更有效,但肯定必须有更多的东西呢?

我认为将"接线"放在配置文件中而不是在代码中手动执行更有意义,原因如下:

    配置在代码外部.

    对连接的更改(告诉您sawmill使用不同的实例Saw)可以简单地对外部(XML)文件进行更改,不需要更改代码,重新编译,重新部署等.

    当你有几十个类和几个注入层时(例如:你有一个web Controller类,它获取一个Service包含你的业务逻辑的类,它使用a DAOSaw从数据库中获取s,并将其DataSource注入其中,等等. ),手动连接协作者是繁琐的,需要几十行代码,除了连接之外什么都不做.

    这有点不那么明确的"好处",但是通过在代码外部进行所有"连接",我认为它有助于向开发人员重新强调依赖注入的核心思想,特别是编码到接口,而不是实现.通过手动接线,可以很容易地回到原来的状态.



5> Jasper Bekke..:

我通常不关心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();

这意味着我仍然集中了耦合并具有其所有优点,而不依赖于更复杂的DI框架或XML配置文件.

推荐阅读
臭小子
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有