【问题标题】:Ninject and private constructorsNinject 和私有构造函数
【发布时间】:2011-09-27 03:35:29
【问题描述】:

我们将 Ninject 用于 IOC。

我们所有的 Repository 对象都可以(并且应该)被模拟用于单元测试。我想强制所有开发人员在与存储库交互时仅对接口进行编码。为此,我想将构造函数设为私有并为构造创建静态访问器工厂方法:

public class SomeRepository : ISomeRepository
{
 private SomeRepository()
 {
 }
 public static ISomeRepository Create()
 {
   return StandardKernel.Get<ISomeRepository>();
 }
}

问题在于:我如何让 Ninject 创建实际的对象?我在同一个项目中有存储库接口和类

【问题讨论】:

  • Obligatory Service Locator link. 在继续你的设计之前,我会读两遍——StandardKernel.Get 看起来像这里的服务定位器。我不会说“这里的服务定位器肯定是错误的”,但 Mark Seemann 会说,如果我是你,我会相信他。
  • 为什么要强制执行私有构造函数?无意冒犯,但我认为您应该信任您的开发人员,并简单地定义某些书面或口头约定,而不是用笨拙的设计使事情过于复杂......
  • @default.kramer:完全同意这篇文章,这就是为什么我不想落入同样的陷阱。由于没有其他方法来创建对象,我打算强制维护开发人员使用 IOC 而不是方向实例化
  • @DanielMarbach:我们有很多维护开发人员,甚至一些功能开发人员,他们只会走最短路线来解决问题,而“new someobject()”是最短路线,而不是设置建立接口和对象之间的映射,然后使用一些奇怪的语法来实例化。这就是现实:(
  • 我再次删除了我的答案,因为我对它不满意。我浏览了一些关于 IoC、DI 和 Ninject 的文档,并得出结论同意 Daniel Marbach 关于代码审查的观点。 Ninject StandardKernel 使用构造期间提供的规则来确定具体实例并将完成的对象返回给调用方法。为什么让SomeRepository 使用内核? SomeRepository 的 IoC 的想法不是不必构造或加载它自己的依赖项吗?我同意代码审查是确保所有开发人员按要求使用内核的方法。

标签: .net constructor inversion-of-control ninject


【解决方案1】:

我们最终会采取以下措施:

public class SomeRepository : ISomeRepository
{
 private SomeRepository()
 {
 }
 public static ISomeRepository CreateForIOC()
 {
   return new SomeRepository();
 }
}

在模块加载期间,我们将 StandardKernel 的 ISomeRepository 接口映射到 CreateForIOC() 方法。

这不会阻止开发人员直接调用 CreateForIOC,但至少会迫使他们 a) 将代码写入接口,b) 意识到 CreateForIOC() 可能不是在实例化对象时调用的正确方法,并且至少要求来自首席开发人员的问题

【讨论】:

  • 除非我没有理解静态“构造函数”的原因,你可以在映射接口时使用内联函数来构造类。 Kernel.Bind&lt;ISomeRepository&gt;().ToMethod(concrete =&gt; { return new SomeRepository(); });。这将为您省去必须在那里放置静电的麻烦。无论哪种方式,您的私有构造函数都必须消失,因为如果它是类中的静态方法或映射中的函数,我认为您不能创建具有私有构造函数的事物的“新”实例。
  • 静态 CreateForIOC 方法在类本身中,因此它可以直接访问构造函数,即使它是私有的。 NInject 将无法使用仅没有辅助静态方法或某些工厂的私有构造函数创建对象
  • 我没有意识到这一点,因为由于隐藏的构造函数,我在 Ninject 调用上遇到了编译错误,所以我认为静态方法也一样。我今天学到了新东西,谢谢。关于实现,我仍然会尝试不让类本身进行构造,而是使用 Ninject 方法来返回实现,这只是我个人的喜好。希望你现在已经把这一切都整理好了:)
【解决方案2】:

为什么不让 Ninject 为任何需要它的对象提供具体的存储库,而不是私有构造函数或工厂方法?

【讨论】:

  • 如果您将存储库类型放在容器中,然后从容器中获取依赖于存储库的应用程序类实例,Ninject 会自动将存储库实例提供给需要它的类型。这通常称为“自动连接”,是 DI/IoC 容器值得学习和使用的部分原因,
【解决方案3】:

您似乎正在尝试使用单例模式。一般来说,单例模式被认为是一种反模式,主要是因为它阻碍了单元测试。依赖注入允许您通过配置创建单例,而无需使用单例模式。

我建议您改为简单地配置 Ninject 以在没有私有构造函数的情况下创建应用程序的单个实例。

【讨论】:

  • @AustinSalonen - 我知道,这就是为什么我说“看起来你正在尝试……”,强调“尝试”。
  • 没有尝试做单例。我只是试图通过提供工厂方法而不是允许直接创建对象来强制对接口进行编码,从而允许开发人员对对象本身进行编码
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-08
  • 2011-04-20
  • 2011-10-30
  • 2017-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多