Dependency injection 马克·希曼';关于私生子注射的说法相互矛盾。需要澄清一下吗

Dependency injection 马克·希曼';关于私生子注射的说法相互矛盾。需要澄清一下吗,dependency-injection,Dependency Injection,我正在读他的书 1) 他说,只有当我们使用国外默认值时,私生子注入才会发生 但在他的书中,第148页的插图显示,当依赖项的默认实现是外部默认或本地默认时,就会发生 那么,当依赖项的默认实现是本地默认值时,反模式也会发生吗 2) (也是在他的书中)他指出,如果一个类有一个可选的依赖项,只要这个依赖项的默认实现是一个好的本地默认值: 但在下一篇文章中,他似乎完全反对使用可选的依赖项,即使默认实现是本地默认值: 就封装而言,这种方法的主要问题是 这看起来像是支农阶层真的拿不定主意 它是否控制其日志依

我正在读他的书

1) 他说,只有当我们使用国外默认值时,
私生子注入才会发生

但在他的书中,第148页的插图显示,当依赖项的默认实现是
外部默认
本地默认
时,就会发生

那么,当依赖项的默认实现是本地默认值时,反模式也会发生吗

2) (也是在他的书中)他指出,如果一个类有一个可选的依赖项,只要这个依赖项的默认实现是一个好的
本地默认值

但在下一篇文章中,他似乎完全反对使用可选的依赖项,即使默认实现是
本地默认值

就封装而言,这种方法的主要问题是 这看起来像是支农阶层真的拿不定主意 它是否控制其日志依赖项的创建。虽然 这是一个简化的示例,如果ILog LogManager返回的实例包装了一个非托管资源,该资源 应该在不再需要时处理

当依赖项的默认实现是本地的时,他在上述摘录中的论点也有效吗?如果是这样,那么也应该避免使用带有本地默认值的可选依赖项

(三) 第147页:

私生子注射的主要问题是使用了一种外国药物 违约我们不能再自由地重用这个类,因为它会拖拉 沿着我们可能不想要的依赖。这也变得更加难以控制 执行并行开发,因为类强烈依赖于它的 依赖性

外部默认值是一个依赖项的实现,该依赖项用作默认值,并在与其使用者不同的程序集中定义。因此,使用外部默认值时,使用者的程序集也将沿着依赖项的程序集拖动

他是否也暗示外国违约会使并行开发更加困难,而本地违约则不会?如果他是,那么这就没有意义了,因为我假设并行开发之所以困难,并不是因为使用者的程序集对依赖项的程序集有硬引用,而是因为使用者类依赖于依赖项的具体实现


谢谢

因为这里有很多问题,我将首先尝试综合我对这个主题的看法,然后根据这些材料明确回答每个问题

合成

当我写作时,我首先试图描述我在野外看到的模式和反模式。因此,书中的模式和反模式首先是描述性的,只是在较小程度上是规定性的。显然,将它们划分为模式和反模式意味着一定程度的判断:)

私生子注射在多个层面上存在问题:

  • 包依赖关系
  • 封装
  • 易用性
最危险的问题与包依赖关系有关。这是我试图通过引入“外国违约”和“本地违约”这两个术语使其更具可操作性的概念。外部默认值的问题在于它们会拖拽硬耦合依赖项,而硬耦合依赖项会导致错误。更明确地处理包管理的一个好资源是

封装级别上很难解释这样的代码:

专用只读ILog日志;
公共消费者(ILog日志)
{
this.log=log??LogManager.GetLogger(“我的”);
}
虽然它保护类的不变量,但问题是在这种情况下,
null
是一个可接受的输入值。情况并非总是如此。在上面的示例中,
LogManager.GetLogger(“我的”)
可能只引入本地默认值。从这个代码片段中,我们无法知道这是否是真的,但为了论证起见,现在让我们假设这一点。如果默认的
ILog
确实是本地默认值,
MyConsumer
的客户端可以传入
null
而不是
ILog
。请记住,封装就是让客户机在不了解所有实现细节的情况下轻松地使用对象。这意味着这是客户端看到的全部内容:

公共消费者(ILog日志)
在C#(和类似语言)中,可以传递
null
而不是
ILog
,它将编译:

var mc=new MyConsumer(空);
通过上述实现,不仅可以编译此文件,而且可以在运行时工作。据我所知,这是件好事,对吗

不幸的是,事实并非如此

考虑另一个具有必需依赖项的类;让我们称之为存储库,只是因为这是一种众所周知(尽管使用过度)的模式:

专用只读IRepository存储库;
公共MyOtherConsumer(IRepository存储库)
{
if(存储库==null)
抛出新的ArgumentNullException(“存储库”);
this.repository=存储库;
}
与封装保持一致,客户端只看到以下内容:

公共MyOtherConsumer(IRepository存储库)
根据以前的经验,程序员可能倾向于编写如下代码:

var moc=新的MyOtherConsumer(空);
这仍然可以编译,但在运行时失败

如何区分这两个构造函数

公共消费者(ILog日志)
公共MyOtherConsumer(IRepository存储库)
不能这样做,但当前存在不一致的行为:在一种情况下,
null
是有效参数,但在另一种情况下,
null
将导致运行时异常。这将降低成本
private readonly ILog log;
public MyConsumer(ILog log)
{
    this.log = log ??LogManager.GetLogger("My");
}