所以我正在尝试学习SOLID原则和依赖注入。我已经阅读了一些关于这个主题的博客文章,我开始明白了一点。但是,有一种情况我无法找到答案,并会尝试在此解释。
我开发了一个用于文本匹配的库,它包含一个类.title
,它有一个名为Matcher
的函数,它在Match
对象中返回结果。此对象包含百分比,已用时间,是否成功等信息。现在从我在依赖注入中理解的是,高级别的类不应该“知道”关于低级别的类或模块。所以我设置了我的库和MatchResult
类来使用Matcher
类的接口,这将允许我使用IoC容器注册它。但是,因为该函数返回Matcher
对象,所以“高级类”必须知道违反DI规则的MatchResult
对象。
我应该如何解决这个问题以及建议的方法是什么?
答案 0 :(得分:7)
DI声明使用接口的类不应该知道有关具体实现的任何细节。但是,MatchResult
不是实现细节,而是接口契约的一部分(DTO,Match
方法的返回类型) - 这没关系。您可以使用另一个以不同方式实现该IMatcher接口的类,但它仍应返回MatchResult
,就像它预期的那样。
答案 1 :(得分:4)
你应该区分DIP,IoC和DI:
DIP - 依赖倒置原则 - 它只说我们应该做什么,不应该做什么
IoC - 控制反转 - 一种使用DIP的方法,它基本上是一种应用DIP的模式.IoC描述了反转控制的不同方式
DI - 它是IoC的具体实现(如服务定位器,上下文查找,工厂)
“高级别课程”必须了解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 应用依赖项反转的“传统”样式之间的对比。如果您来自“高级模块依赖于低级模块”的背景(并且您使用术语“模块”),那可能会更清楚。但如果那不是以前的“传统”,那么你是什么“反转?什么都没有。
所有这些细节仍然有意义,但是当你第一次尝试学习这些概念时,它们会非常混乱。我的建议是应用这部分,就像你已经存在的那样:取决于抽象。
如果你这样做那么你就应用了这个原则,因为无论“高级模块”和“低级模块”是什么,你的类都不会过于依赖其他类 - 高级,低级或者其他。