限制和自由之间的决定(接口和依赖注入)

时间:2018-06-06 23:11:08

标签: c# .net oop computer-science

据我所知,C#中的接口可以被认为是派生类必须遵循的契约或承诺。这允许不同的对象在调用重写方法时以不同的方式运行。

DI,我是如何理解的,它提供了通过能够通过ctor,属性或方法注入依赖关系(通常通过容器)来减少依赖关系的能力。

似乎他们是自由与克制之间完全相反的两种力量。我可以创建一个契约,说派生类必须遵循这些特定的指导原则,这些指南本质上是限制性的,这允许我注入依赖关系(我知道依赖关系必须继承接口但仍然......),这本质上是允许的。我可以让所有东西都可以注射,并且可以改变课程。

我想我的问题是你决定你想要的限制程度的过程是什么?当你想要完全自由时,何时使用多态或DI的接口更重要?你在哪里划线?当您希望结构(方法和属性)在不同的派生类和DI之间对齐时,如果参数可能大不相同,是否可以使用接口?

编辑:

也许DI是错误的例子。假设我有一个IPlugin和插件工厂。所有插件都需要相同的信息,工作方式相同等。因此使用界面是有意义的。现在,一个插件工作原理相同,但需要不同的参数或不同的数据,但最终结构相同,即加载,运行等。

我想传递一个命令对象,它可以暴露插件需要的不同参数(使用DI),然后每个插件都可以使用该命令对象的属性,但事实上我可以使用截然不同的参数注入命令对象有点打破了首先签订合同的整个想法。那会是犹太人吗?

2 个答案:

答案 0 :(得分:0)

  

DI,我是如何理解的,它提供了通过能够通过ctor,属性或方法注入依赖关系(通常通过容器)来减少依赖关系的能力。

不正确的。静态代码分析显示依赖性仍然存在。 DI只会改变你最终得到一个实例到对象的方式。如果您的ctor说的是期望某个特定类的对象,那么您对该类型有依赖性,但您还有强耦合错误的类。但是,如果您的ctor期望某个interface的类型,那么您对该合约定义有依赖性,但到实际实现(失去耦合)。

  

据我所知,C#中的接口可以被认为是派生类必须遵循的契约或承诺。这允许不同的对象在调用重写方法时以不同的方式运行。

是的,但它们也是一种通过隐藏不必要的细节来抽象组件的方法,比如一个类不能。这就是为什么在相当大的系统中,有一个MyContracts.dll,你可以在其中定义所有interface s;并说BusinessLogic.dll和ClientStuff.dll。 ClientStuff依赖于契约,但它并不关心BusinessLogic.dll可能具有的其他依赖项的实际实现和可能的数量(典型的WPF或WCF应用程序)。

  

当您想要完全自由时,何时使用多态或DI的接口更重要?你在哪里划线?当您希望结构(方法和属性)在不同的派生类和DI之间对齐时,如果参数可能大不相同,是否可以使用接口?

DI不提供比非DI系统更多的自由。但是我认为你可能会对术语或概念感到困惑。 DI总是好的。如上所述,在类类型上注入接口更好。

  

我可以创建一个合同,说明派生类必须遵循这些特定的准则,这些准则本质上是限制性的,而DI允许我注入依赖关系

合同是合同,无论是接口形式还是抽象类合同。如果构造函数(构造函数注入)或属性(属性注入)要求MyDbConnection那么就会设置一个关于可以注入什么的要求更多而不是仅仅期望一个{ {1}}。

我认为你对DI的看法可能有问题。 DI并不总是注入类和接口不只是为了多态。后者是一个常见的错误。 DI与“限制性”无关。这取决于您期望注入的类型。

实际上,期望一个具体的类对象或由抽象类派生的东西被注入比注入一个接口更多“限制性”,这是因为接口可以在更多场景中重用的本质。例如并不是说你会注射一个IMyDbConnection之前的WPF但不会在WPF和MVVM中发挥重要作用。

制约:

INotifyPropertyChanged

没有那么严格

public EditPatientViewModel (SqlPersistenceService svc) {}
  

在限制和自由之间做出决定(接口和依赖注入)

这完全取决于您,但如果您注入接口,那么您将获得:

  • 合同与实施之间的脱钩以及随之而来的所有行李
  • 改进抽象 - 隐藏不必要的细节

答案 1 :(得分:0)

我正在阅读"单元测试艺术"作者:Roy Osherove,我认为他回答了我的问题。

他在测试和提及中讨论DI,有些人认为这会损害面向对象的设计原则(即打破封装)。

面向对象的原则是对API的最终用户强制执行约束,以便正确使用对象模型并防止无意使用。例如,测试添加另一个最终用户。在某些地方封装这些外部依赖项而不允许任何人更改它们,拥有私有构造函数或密封类,具有非虚拟方法都是过度保护设计的经典标志。

我认为我的问题是,我觉得注入过多的依赖关系破坏了封装原则,但添加这些依赖关系以最终用户需要功能(如测试)的方式迎合最终用户而不是t打破任何封装规则。