在过去的几天里,我已经阅读了很多关于依赖注入/控制/反转依赖的反转的内容。我认为,现在我对这个概念的理解要好得多。但我仍然没有从维基百科得到以下内容:
一个。高级模块不应该 依赖于低级模块。都 应该取决于抽象。 B.抽象不应该依赖于细节。细节应该 取决于抽象。
我理解高级模块的部分不应该 依赖于低级模块。但是,我对抽象和细节感到困惑。有人请为我简化它们。感谢。
答案 0 :(得分:35)
这意味着如果细节发生变化,它们不应该影响抽象。抽象是客户端查看对象的方式。确切地说,对象内部发生的事情并不重要。让我们以汽车为例,踏板,方向盘和变速杆是发动机内部发生的事情的抽象。他们并不依赖于细节,因为如果有人将我的旧发动机更换为新发动机,我仍然可以在不知道引擎发生变化的情况下开车。
另一方面,细节必须符合抽象所说的内容。我不想实现一个突然导致制动器使汽车速度加倍的发动机。我可以以任何我想要的方式重新制动刹车,只要从外部他们的行为方式相同。
答案 1 :(得分:3)
抽象依赖于细节的一个有趣情况是,当您定义继承自IDisposable的接口时。看看以下抽象:
public interface ICustomerRepository : IDisposable
{
Customer GetById(Guid id);
Customer[] GetAll();
}
注意 :IDisposable
是特定于.NET的界面,但您可以轻松想象您的界面包含Dispose
方法本身而不是继承自这样的界面。
ICustomerRepository
实施IDisposable
可能会很方便。这样任何调用者都可以处置存储库,这样实现就可以处理它在内部使用的连接或工作单元。
然而,现在编写了一个特定实现的接口,因为所有ICustomerRepository
实现都需要清理任何资源并不明显。因此,接口泄漏了实现细节,因此违反了依赖性倒置原则。
答案 2 :(得分:1)
抽象示例和细节:流提供读取令牌的接口。这是一种抽象。
流的流实现必然会实现抽象定义的接口:这就是它依赖于它的原因。如果它提供了一个不同的接口(一次只能读取100个字符),它就不能声称实现相同的抽象。
答案 3 :(得分:1)
想想你需要调用的工作,以及你当前编码的距离。那里有一个频谱;你在它上面的位置代表了调用该功能所需的工作量。
抽象将该位置移近您正在编写的代码。例如,如果必须调用Web服务,则可以1)直接在需要使用它的地方编写调用代码,或者2)将这些细节放在抽象(例如接口)之后。
在这种情况下,#1使您更接近频谱上的Web服务,而#2则让您更接近您的工作。抽象可以说是衡量你需要多长时间才能理解你需要做的工作。
这意味着每件作品都可以被抽象出来,以便它与使用它的代码“更接近”。通过使操作的双方都依赖于抽象,它们都变得更容易理解,并且双方都不必知道它们之间的差距 - 这是抽象的工作。
哇,这很抽象。