与SOLID和Dependecy Injection混淆
所以我正在尝试学习SOLID原理和依赖注入。 我已经阅读了关于这个主题的一些博客文章,并且我开始了解了一些。 但是,有一种情况我找不到答案,并会在这里尝试解释。
我开发了一个库来进行文本匹配,它包含一个Matcher
类,它有一个名为Match
的函数,它将结果返回给MatchResult
对象。 此对象包含百分比,已过时间,是否成功等信息。 现在从我在依赖注入中理解的是,高级类不应该“知道”低级类或模块。 所以,我建立了我的图书馆和Matcher
类使用接口的Matcher
类,这将允许我使用Ioc容器注册。 但是,因为该函数正在返回MatchResult
对象,所以“高级类”必须知道有关打破DI规则的MatchResult
对象。
我应该如何着手解决这个问题,以及推荐的方法是什么?
“高级别”和“低级别”是与依赖性倒置相关的术语,其与依赖性注入有关,但是是不同的概念。 他们都有首字母缩写“DI”,而“D”都代表“依赖”,因此可能会造成一些混淆。
(我这样想 - 依赖注入是一种实现依赖倒置的方法。)
但在我看来,定义依赖性反转时使用的术语对于尝试理解概念的.NET程序员来说可能会非常混乱。 这是适用的,但是.NET开发人员不使用某些术语。
根据维基百科引用的罗伯特马丁的定义,
高级模块不应该依赖于低级模块。 两者都应该依赖于抽象。 抽象不应该依赖细节。 细节应该取决于抽象。
什么是“高级模块”和“低级模块?” 如果你发现混淆你并不孤单。 我们并不真的使用这些条款。 我们可以真正理解和应用的部分是我们应该依赖抽象。
在MatchResult
的情况下,如果它只是一些属性的容器,那么它可能足够抽象。 一段时间以来,DTO一直是一种常见的做法,所以如果时间已经显示我们需要将它们包装在界面中,那么现在就会出现这种模式。 它没有伤害,但通常没有必要。
回到依赖倒转 - 真正的混乱来自名字本身。 什么是倒立? 当你看到维基百科页面上的图表时,我的建议是远离致盲图表。
马丁用这种方式解释他使用“倒置”这个词(回到他关于这个问题的原始论文)
有人可能会质疑我为什么使用“倒置”这个词。 坦率地说, 这是 因为更多传统的软件开发方法 (如结构化分析和设计) 倾向于创建软件结构,其中高级模块依赖于低级模块,并且抽象依赖于细节 。 实际上,这些方法的目标之一是定义描述高级模块如何调用低级模块的子程序层次结构。 图1是这种层次结构的一个很好的例子。 因此, 设计良好的面向对象的程序的依赖性结构相对于通常由传统程序方法产生的依赖性结构是“倒置的”。
换言之,反演是应用依赖性反演与不使用依赖性反演的“传统”风格之间的对比。 如果你来自“高级模块依赖于低级模块”的背景(并且使用术语“模块”),那么这可能会更清晰。但是,如果这不是你以前的“传统”,那么你是什么“反转? 没有。
所有这些细节仍然有意义,但是当你第一次尝试学习这些概念时,这些细节非常混乱。 我的建议是应用这部分,因为你已经是:取决于抽象。
如果你这样做,那么你应用这个原则,因为无论“高级模块”和“低级模块”是什么,你的类不会太依赖于其他类 - 高级,低级或其他类。
DI指出使用接口的类不应该知道具体实现的任何细节。 然而, MatchResult
不是实现细节,而是接口契约的一部分(DTO, Match
方法的返回类型) - 没关系。 你可以有一个额外的类以不同的方式实现IMatcher接口,但它应该返回一个MatchResult
,就像它期望的那样。
你应该区分DIP,IoC和DI:
DIP - 依赖倒置原则 - 它只是说我们应该做什么,不应该做什么
IoC - 控制反转 - 使用DIP的一种方式,它基本上是一种应用DIP的模式.IoC描述了反转控制的不同方式
DI - 它是IoC的具体实现(如服务定位器,上下文查找,工厂)
DIP,IoC,DI
“高级别”必须了解打破DI规则的MatchResult对象。
不,这不会违反DIP规则。 你不应该知道具体的实现 - 在这种情况下你应该使用接口(即IMatcher)并创建实现这个接口的类。
然后你可以使用任何实现这个接口的类:
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
的实现,你也可以使用IMatchResult
接口而不是特定的实现来返回你想要的实现。