【问题标题】:Dependency Injection as a Language Feature?依赖注入作为语言功能?
【发布时间】:2016-04-15 05:37:11
【问题描述】:

是否有任何现有的现代编程语言明确将依赖注入作为语言功能,如果有,是否有任何示例说明此类编程语言如何使用其语法将程序依赖项与其具体实现分开?

(请注意:我不是在寻找一个 DI/IOC 框架——我实际上是在寻找一种在语言中内置了这个功能的编程语言)。

【问题讨论】:

    标签: dependency-injection inversion-of-control


    【解决方案1】:

    您不会发现依赖注入是一种语言功能,因为它通常被视为一种设计模式。设计模式是作为缺少语言功能的解决方法出现的——例如,如果您将一流的类型作为语言功能,则不需要工厂模式(请参阅Norvig's presentation 的第 12 页),如果您将多方法作为语言功能,则不需要双重调度模式。

    以 DI 为设计模式的语言特性是“参数模块”。请参阅与 Gilad Bracha 的语言有关的 discussion of modules 与 DI Newspeak

    【讨论】:

    • 另见关于“设计模式是编程语言弱点的标志”的讨论——oreillynet.com/onlamp/blog/2006/10/…
    • 某些语言确实提供服务定位器作为语言功能。例如,python。
    • @Arafangion 你的意思是导入语句docs.python.org/reference/index.html,还是语言中的其他东西(而不是库)?拥有模块的搜索路径比服务位置少很多,依赖注入不等于服务位置。
    • 您可以在运行时(随时)更改模块的内容,这些更改将影响导入它的每个模块。这与告诉服务定位器“如果请求 IFoo,请提供 Bar 而不是通常的 Foo”非常相似。
    • “如果你有一流的类型作为语言特性,你就不需要工厂模式”这个理论的任何例子或证明?
    【解决方案2】:

    我并不是说听起来像个混蛋,但每种 OO 语言都支持依赖注入。不需要特殊语法。只需使用它们的依赖项构建您的对象(或稍后设置它们的依赖项)。

    实际上,您可以在程序顶部附近的某个位置连接所有依赖项 - 不一定是 main(),而是靠近顶部。

    【讨论】:

    • 我不是在寻找一种可以让你实现依赖注入的编程语言,我实际上是在寻找一种说“我想创建一个 IFoo”的语言,然后编译器/运行时决定什么在编译时没有指定具体类就被创建了。
    • 啊,我认为您正在寻找自动装配或自动服务发现的语言支持。我的错。
    • 你的意思是“控制反转”?您甚至不需要 OO,可以将每个模块编写为仿函数/工厂并在我想的组合根中初始化它们吗? “依赖注入”是指当您不必手动(将代码写入/在您的大脑中)遍历依赖图并以正确的顺序初始化它们时,一些框架会为您解决这个问题。我想 IoC 是比 DI 更重要的东西,这只是一种方便的方法。但是,当您需要 DI 时,您的组合根可能会变得非常大。
    • 您所描述的通常称为“依赖注入框架”,即进行依赖注入的框架。但是手动依赖注入也是一回事。控制反转是一个更广泛的主题,还包括事件回调等内容。
    【解决方案3】:

    Noop 应该是这样做的,但我还没有看到语言规范(在我找到它之前我的耐心已经耗尽)。

    【讨论】:

    【解决方案4】:

    可以说 Scala 在特性和自类型注释的帮助下支持开箱即用的依赖注入。看看蛋糕图案:

    http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di/

    基本上,这种方法使用具有声明依赖关系的特征(通过使用自类型)让编译器完成将它们连接在一起的工作。

    这是声明注册表:

    object ComponentRegistry extends 
      UserServiceComponent with 
      UserRepositoryComponent 
    {
      val userRepository = new UserRepository
      val userService = new UserService
    }
    

    ...注册用户存储库:

    trait UserRepositoryComponent {
      val userRepository: UserRepository
    
      class UserRepository {
        ...
      }
    }
    

    ...以及依赖于存储库的用户服务组件:

    trait UserServiceComponent { 
      this: UserRepositoryComponent => 
    
      val userService: UserService  
    
      class UserService {
        ... 
      }
    }
    

    【讨论】:

    • +1 对于 Scala。看看 AWESOME 演讲,Dead-Simple Dependency Injection Runar 超级聪明,也很搞笑:“控制反转,这实际上只是一种自命不凡的方式来表达‘争论’”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-29
    • 2016-01-20
    • 2021-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-07
    相关资源
    最近更新 更多