代码之家  ›  专栏  ›  技术社区  ›  mikemay

为什么动态语言不需要IOC容器

  •  41
  • mikemay  · 技术社区  · 16 年前

    有人在第68号牧人密码播客上, http://herdingcode.com/herding-code-68-new-year-shenanigans/ ,声明IOC容器没有Python或Javascript的位置,也没有类似的词语。我假设这是传统的观点,它适用于所有动态语言。为什么?动态语言的哪些方面使得IOC容器变得不必要?

    9 回复  |  直到 8 年前
        1
  •  50
  •   Community Mohan Dere    14 年前

    IoC提供了一种机制,当一个对象在另一个类上调用“new”时,可以打破耦合。这种耦合将调用对象与它实现的任何接口的实例化实现联系起来。

    在静态语言中按名称引用类时(调用 new 在它上面),没有含糊不清的地方。这是一个 紧耦合

    在动态语言中调用 new X X 在执行点”。这是一个 ,因为它只和名字有关 十 .

    这种微妙的差异意味着在动态语言中,您通常可以改变 十

    然而,就我个人而言,我发现IoC有两个优势,那就是依靠动态语言来允许注入是无法实现的。

    通过构造函数传递依赖项的一个副作用是,最终得到的“构建块”类非常解耦、可重用且易于测试。他们不知道要在什么上下文中使用它们,所以你可以到处重用它们。

    就像Jrg W Mittag说的。。

        2
  •  27
  •   Stefan Arentz    16 年前

    我有不同的意见。我认为IOC容器在动态语言中肯定有作用。

    我不同意这样的观点,即语言是动态的,不需要对象的结构清晰的组合。或者动态语言“提供”相同的功能。

    即使在动态语言中,我也希望将组件“连接”在一起。不需要在这些组件之间建立严格的依赖关系。或者甚至不指定这些组件的实际实现类。

        3
  •  20
  •   Doug    14 年前

    我同意上面的答案,但我想我也应该在这里插一点关于测试的内容:

    在子系统之间存在交互的复杂系统中,依赖注入是我所知道的进行单元测试的最佳方法。

    应该有两种测试:

    • 在任何环境中运行并测试单个代码单元逻辑的单元测试。
    • 测试组合应用程序逻辑的集成/功能测试。

    :

    // Do this every time you want an instance of myServiceType
    var SystemA = new SystemA()
    var SystemB = new SystemB()
    var SystemC = new SystemC(SystemA, "OtherThing")
    var SystemD = new SystemD(SystemB, SystemC)
    var IRepo = new MySqlRepo()
    var myService = new myServiceType(SystemD, IRepo)
    

    // Do this at application start
    Container.Register(ISystemA, SystemA)
    Container.Register(ISystemB, SystemB)
    Container.Register(ISystemC, SystemC)
    Container.Register(ISystemD, SystemD)
    Container.Register(IRepo, MySqlRepo)
    Container.Register(myServiceType)
    
    // Do this any time you like
    var myService = Container.resolve(myServiceType)
    

    现在,我们为什么不在许多动态语言中看到国际奥委会?

    我想说的原因是我们在这些语言中没有看到太多依赖注入。

    …那是因为在他们身上做的测试通常是不存在的。

    有 没有借口 对于没有单元测试或代码覆盖率低的单元测试的项目。

    guice网站上有一篇关于DI的优秀文章: http://code.google.com/p/google-guice/wiki/Motivation

    动态语言并不能解决这些问题。

    • IoC对事物是有用的,但主要用于实现DI
    • 国际奥委会 不 xml配置文件&燃气轮机_&书信电报;
    • DI对测试很有用
    • 没有IOC表示没有DI,这表示没有良好的测试。
        4
  •  17
  •   Jörg W Mittag    16 年前

    因为它们已经融入了语言。

    IoC容器提供两种功能:

    • 动态绑定

    动态绑定已经是动态语言的一部分,而动态语言已经是一种动态语言。因此,IoC容器根本没有意义:语言已经是IoC容器了。

    请注意我是 谈论依赖注入或控制反转。DI和IoC是 因为完全相同的原因,动态语言和静态语言一样重要。我说的是IoC容器和DI框架。那些 是不必要的 设计原则

        5
  •  4
  •   Alex Craft    15 年前

    IoC提供了一种机制,当一个对象在另一个类上调用“new”时,可以打破耦合。

    这是对国际奥委会的天真看法。通常,IoC还解决:

    • 依赖项解析
    • 自动组件查找和初始化(如果在IoC中使用'require',则会出现问题)
    • 不仅适用于单例,也适用于动态范围
    • 99.9%的时间对开发者来说是看不见的
    • 无需app.config

    全文 You underestimate the power of IoC

        6
  •  4
  •   Remo H. Jansen    10 年前

    我相信IoC容器在大型JavaScript应用程序中是必要的。您可以看到一些流行的JavaScript框架包括一个IoC容器(例如 $injector

    我已经开发了一个名为InversifyJS的IoC容器,您可以在 http://inversify.io/ .

    一些JavaScript IoC容器声明要注入的依赖项如下:

    import Katana from "./entitites/katana";
    import Shuriken from "./entitites/shuriken";
    
    @inject(Katana, Shuriken) // Wrong as Ninja is aware of Katana and Shuriken!
    class Ninja {
      constructor(katana: IKatana, shuriken: IShuriken) {
        // ...
    

    这种方法的优点是没有字符串文字。不好的是,我们的目标是实现解耦,我们只是添加了一个 到文件中的忍者是宣布,这不是真正的解耦。

    InversifyJS为您提供真正的解耦。ninja.js文件永远不会指向katana或shuriken文件。但是,它将指向接口(在设计时)或字符串文本(在运行时),这是可以接受的,因为它们是抽象和 depending upon abstractions 这就是DI的意义所在。

    import * as TYPES from "./constants/types";
    
    @inject(TYPES.IKATANA, TYPES.ISHURIKEN) // Right as Ninja is aware of abstractions of Katana and Shuriken!
    class Ninja { 
      constructor(katana: IKatana, shuriken: IShuriken) {
        // ...
    

    js内核是应用程序中唯一知道生命周期和依赖关系的元素。我们建议在名为 inversify.config.ts 并将文件存储在包含应用程序源代码的根文件夹中:

    import * as TYPES from "./constants/types";
    import Katana from "./entitites/katana";
    import Shuriken from "./entitites/shuriken";
    import Ninja from "./entitites/ninja";
    
    kernel.bind<IKatana>(TYPES.IKATANA).to(Katana);
    kernel.bind<IShuriken>(TYPES.ISHURIKEN).to(Shuriken);
    kernel.bind<INinja>(TYPES.ININJA).to(Ninja);
    

    这意味着 应用程序中的所有耦合都发生在一个独特的位置 :的 inversify.config.ts 文件这非常重要,我们将用一个例子来证明这一点。让我们想象一下,我们正在改变游戏的难度,我们只需要进入 inversify.config.ts 并更改Katana绑定:

    import Katana from "./entitites/SharpKatana";
    
    if(difficulty === "hard") {
        kernel.bind<IKatana>(TYPES.IKATANA).to(SharpKatana);
    } else {
        kernel.bind<IKatana>(TYPES.IKATANA).to(Katana);
    }
    

    要付出的代价是字符串文本,但如果在包含常量的文件中声明所有字符串文本,则可以降低此代价( like actions in Redux ). 好消息是在将来 could end up being generated by the TS compiler ,但这目前掌握在TC39委员会手中。

    here .

        7
  •  3
  •   Pace    16 年前

    this article 换个角度。

        8
  •  3
  •   kyoryu    16 年前

    这个合成层在动态语言(如Python或Javascript)中相对自然地存在(考虑Javascript在很大程度上基于Scheme)。

    您可能会提出一个很好的论点,即IoC容器只是解释器模式的泛化。

        9
  •  0
  •   Matt Fenelon    15 年前

    Herding Code 82 (6/6/10)比较了Ruby和.NET,并详细讨论了.NET比Ruby需要更多IOC/DI的程度。

    推荐文章