困惑于SOLID和Dependecy Injection

时间:2016-07-19 11:24:45

标签: c# .net dependency-injection inversion-of-control solid-principles

所以我正在尝试学习SOLID原则和依赖注入。我已经阅读了一些关于这个主题的博客文章,我开始明白了一点。但是,有一种情况我无法找到答案,并会尝试在此解释。

我开发了一个用于文本匹配的库,它包含一个类.title,它有一个名为Matcher的函数,它在Match对象中返回结果。此对象包含百分比,已用时间,是否成功等信息。现在从我在依赖注入中理解的是,高级别的类不应该“知道”关于低级别的类或模块。所以我设置了我的库和MatchResult类来使用Matcher类的接口,这将允许我使用IoC容器注册它。但是,因为该函数返回Matcher对象,所以“高级类”必须知道违反DI规则的MatchResult对象。

我应该如何解决这个问题以及建议的方法是什么?

3 个答案:

答案 0 :(得分:7)

DI声明使用接口的类不应该知道有关具体实现的任何细节。但是,MatchResult不是实现细节,而是接口契约的一部分(DTO,Match方法的返回类型) - 这没关系。您可以使用另一个以不同方式实现该IMatcher接口的类,但它仍应返回MatchResult,就像它预期的那样。

答案 1 :(得分:4)

你应该区分DIP,IoC和DI:

DIP - 依赖倒置原则 - 它只说我们应该做什么,不应该做什么

IoC - 控制反转 - 一种使用DIP的方法,它基本上是一种应用DIP的模式.IoC描述了反转控制的不同方式

DI - 它是IoC的具体实现(如服务定位器,上下文查找,工厂)

DIP, IoC, DI

  

“高级别课程”必须了解MatchResult对象   这打破了DI的规则。

不,这不会破坏 DIP 规则。 您不应该知道具体的实现 - 在这种情况下,您应该使用接口(即IMatcher)并创建实现此接口的类。

然后您可以使用任何实现此接口的类:

 public TypeFE() {
    initComponents();
    setLocationRelativeTo(null);
    setResizable(false);
    setTitle("Type");
    Allarticle allarticle = new Allarticle();
    allarticle.importFrom("article.txt");
    Set <String> marticles;
    marticles = allarticle.getTypeForFabricant(Article.mFabricant);
    for(String article : marticles){
        typebox.addItem(article);
    }


}

在您的情况下,public class Test { private IMatcher _matcher; public Test(IMatcher matcher) // here you can pass any class than implements IMatcher, and you don't know specific implementation of this class - this is DI { this._matcher = matcher; } } 只是某些实现返回的结果。

如果要返回不同的MatchResult实现,还可以使用MatchResult接口而不是特定实现来返回所需的实现。

答案 2 :(得分:4)

“高级别”和“低级别”是与dependency inversion相关联的术语,它与依赖注入有关,但是是不同的概念。它们都有首字母“DI”,两者中的“D”代表“依赖”,因此它们可能造成一些混乱。

(我想到这一点 - 依赖注入是实现依赖性反转的一种方式。)

但在我看来,定义依赖倒置时使用的术语可能会让试图理解这个概念的.NET程序员感到困惑。它是适用的,但.NET开发人员中没有使用某些术语。

来自罗伯特·马丁的定义,如维基百科所引用,

  

高级模块不应该依赖于低级模块。两者都应该   取决于抽象。   抽象不应该依赖于细节。细节应该取决于   抽象。

什么是“高级模块”和“低级模块?”如果你发现令人困惑,你并不孤单。我们并没有真正使用这些条款。我们真正理解和应用的部分是我们应该依赖于抽象

MatchResult的情况下,如果它只是一些属性的容器,那么它可能足够抽象。 DTO在一段时间内已经成为一种常见的做法,所以如果时间已经显示我们需要将它们包装在接口中,那么现在就会出现这种模式。它没有伤害,但通常没有必要。

回到依赖倒置 - 真正的困惑来自名称本身。倒是什么?当您看到维基百科页面上的图表时,我的建议是远离炫目的图表。

Martin explains他以这种方式使用“倒置”这个词(回到他关于这个主题的原始论文)

  

有人可能会质疑为什么我使用“反转”这个词。坦率地说,   因为比较传统的软件开发方法等   结构化分析和设计,倾向于创建软件结构   哪些高级模块依赖于低级模块,其中   抽象取决于细节。确实是这些目标之一   方法是定义描述如何的子程序层次结构   高级模块调用低级模块。图1是一个   这种层次结构的好例子。因此,的依赖结构   精心设计的面向对象程序相对于“倒置”   通常由传统结果产生的依赖结构   程序方法。

换句话说, inversion 是应用依赖项反转和 not 应用依赖项反转的“传统”样式之间的对比。如果您来自“高级模块依赖于低级模块”的背景(并且您使用术语“模块”),那可能会更清楚。但如果那不是以前的“传统”,那么你是什么“反转?什么都没有。

所有这些细节仍然有意义,但是当你第一次尝试学习这些概念时,它们会非常混乱。我的建议是应用这部分,就像你已经存在的那样:取决于抽象。

如果你这样做那么你就应用了这个原则,因为无论“高级模块”和“低级模块”是什么,你的类都不会过于依赖其他类 - 高级,低级或者其他。