【问题标题】:Any need for dependency injection in Dynamic Languages?动态语言中是否需要依赖注入?
【发布时间】:2010-12-29 16:38:42
【问题描述】:

为了编写可测试的 C# 代码,我大量使用 DI。

但是最近我一直在使用 IronPython,发现你可以模拟任何方法/类/函数等...你喜欢,不再需要 DI。

对于 Python 等动态语言是否如此?

代替:

class Person(Address) {
...

你可以拥有:

class Person() {
...
    // Address initialised in here.

对于动态语言,因此根本不需要遵循动态语言的手动 DI。

对此有何建议?

【问题讨论】:

标签: dependency-injection dynamic-languages


【解决方案1】:

依赖注入也是关于如何将事物连接在一起 --- 这与依赖对象的可模拟性无关。有一个 Foo-instance 需要一个 someBar-connection 直接实例化它,并让它完全忽略它如何获取该连接作为只要它它。

如果您使用依赖注入,您会获得更好的可测试性。但反之则不然。通过覆盖任何东西来更容易测试并不会带来依赖注入的其他优点。正是出于这些原因,有许多适用于 Python 的组件/DI 框架可用。

【讨论】:

  • 依赖注入的“其他优点”是什么?
【解决方案2】:

我强烈不同意您关于动态类型语言不需要依赖注入的说法。 DI 有用和必要的原因完全独立于语言的打字规则。

主要区别在于动态类型语言中的 DI 简单而轻松:您不需要重量级的框架和大量的 XML 配置行。

例如,在 Ruby 中,只有两个 DI 框架。两者都是由 Java 程序员编写的。 单个项目都没有使用这两个框架。甚至不是那些框架的作者

然而,在 Ruby 中到处都在使用 DI。

这两个框架的作者 Jamis Buck 在 2008 年的 RubyConf 上发表了一个名为 Recovering from Enterprise 的演讲,讲述了他如何以及为什么编写这些框架以及为什么这是一个坏主意,这是非常值得一看。如果您想阅读,还有accompanying blog post。 (每次他说“Ruby”时,只需替换“Python”,一切都一样有效。)

【讨论】:

  • “gazillion”不是很夸张吗?我在 C# 中大量使用 DI,而我很少使用 XML 配置(如果有的话)。
  • 是的,这绝对是夸大其词。这也是一种过时的夸张,因为后 .NET2 和后 Java5 DI 框架倾向于使用属性/注释而不是 XML。基本思想是这样的:在 Java 或 C# 中动态地连接起来很困难。这就是为什么使用 DI 框架是有意义的:我不关心解析 XML 或处理注释/属性,所以我让其他人来做这项工作,他们喜欢那种东西。但是在 Python 或 Ruby 中,一切都是总是动态连接的,无论如何语言本身已经是一个DI框架。无需在上面再放一个。
  • 另一种思考方式:DI 框架的作用是什么?它将独立的组件粘合在一起。我们通常称将独立组件粘合在一起是什么?脚本!它如何确定要做什么?它读取一个 XML 文件或一组注释。我们通常称一组说明如何将事物粘合在一起的指令是什么?一个脚本!执行这些指令的是脚本解释器。因此,DI 框架只是(通常很糟糕,尤其是在使用 XML 时)脚本语言的解释器。但在 Python 中,我们已经拥有:Python!
  • 我的 Ninject / StructureMap 和其他 IOC 容器中没有 XML... 抱歉,但是在 .NET MVC3 / MVC4 中进行现代开发非常简单。 XML 糟糕,90 年代被调用并希望他们的 XML 代码回来(我夸大了,但我使用 Ninject 和 Structurmap 进行零 XML 配置)。但是,是的,您在关于使用动态语言进行 DI 的 OP 问题中是正确的。
  • "主要区别在于动态类型语言中的 DI 简单且无痛:您不需要重量级框架" 您不需要需要静态类型语言中的框架任何一个。 DI 是一个比 ioc 容器更通用的概念(这似乎是您的想法)。
【解决方案3】:

我会再试一次。我的最后一个答案错过了问题一英里,并且偏离了主题。

使用伪代码,依赖注入说:

class Person
  def Chat() { 
    someOperation("X","Y","Z")
  end
end
...
Person.new().Chat()

并与:

class Person
  initialize(a,b,c)
    @a=a
    @b=b
    @c=c
  end
  def Chat()
    someOperation(@a,@b,@c)
  end
end
...
Person.new("X","Y","Z").Chat()

,.,并且通常将对象和调用放入不同的文件以用于 SCM。

“X”、“Y”或“Z”是否可模拟(......如果它们是对象......(!)......(!)......)与是否迪很好。真的。 :-)

DI 在 Python 或 Ruby 中更容易,就像许多其他任务一样,因为有更多的脚本方法,就像 Jörg 所说的那样;当然也少了一种文化和一种倾向,即常量和适配器将被填充到模型和全局常量中。

实际上,对我来说,DI 是将这些应用程序参数、API 常量和工厂分离到单独的文件中的第一步,以帮助您的修订跟踪报告看起来不那么像意大利面条(“AppController 上的那些额外签入是否需要更改?配置..?还是更新代码...?”)和更多信息,更易于阅读。

我的建议:继续使用 DI... :-)

【讨论】:

    【解决方案4】:

    我认为您提出的问题似乎与最佳实践有关,但实际上与运行时性能有关。

    摆脱依赖注入?软件发布经理晚上怎么睡觉?

    要执行的功能测试肯定会使程序减慢一到两次。

    // my generic function entry point - IronPython
    if func="a":
      ...
    if func="b":
      ...
    if func="c":
      ...
    

    您可以将标准 Python 与类一起使用...或者您可以将函数指针分配给函数指针成员。到底是怎样的野兽……??我知道我知道。我认为 Python 很难定义,但我喜欢它。而且我喜欢并高度重视依赖注入,而不是我长期以来一直想为这种做法分配如此冗长的名称。

    【讨论】:

    • 读到这让我很困惑。
    猜你喜欢
    • 2016-01-20
    • 2020-04-14
    • 1970-01-01
    • 2020-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-04
    • 1970-01-01
    相关资源
    最近更新 更多