Robert解释说,当高级模块依赖于较低级别的模块时,较低级别模块的更改可能会导致更高级别的模块也发生变化.他通过以下示例演示了这一点:
public class Button { private Lamp lamp; public void Poll(){ if(/*some condition*/) Lamp.TurnOn(); } }
关于这段代码罗伯特说:“Button类直接依赖于Lamp类.这种依赖性意味着Button会受到Lamp变化的影响.”
正如我所看到的,我们可能会对Lamp类进行两种可能的更改:
1)我们可能想要更改类的内部实现,但不会影响公共接口.
2)我们可能决定更改公共接口以将参数传递给TurnOn方法.
我不明白的是,在第一种情况下,为什么我们的更改会导致Button类的更改? Lamp的公共接口没有改变,为什么Button需要改变?
在第二种情况下,我可以看到这将需要我们更改Button.但在这种情况下,取决于抽象如何改变这一点?当然,如果我有正当理由将接口更改为Lamp,那么我也将改变Lamp和Button所依赖的抽象中的界面.在这种情况下,我必须改变Button,因为它依赖的抽象已经改变.
我意识到DIP还有其他好处,例如更高级别模块的可重用性,更高级别模块的接口所有权以及在运行时选择依赖项实现的能力,但是我很难理解DIP如何减少依赖的需求当到较低级别模块的接口改变时改变的模块和/或从属模块中的内部改变可能导致更高级别模块的改变的原因.
我相信DIP为这个例子带来的重要区别是界面的所有权.特别是哪个层拥有接口,其中Button是客户端而Lamp是服务器.在具体类Lamp的依赖项中,接口(.TurnOn())归Lamp类(服务器)所有.因此,可以决定仅根据服务器的需要更改.TurnOn()方法,因为它拥有该方法,这将需要后续更改Button类(客户端).
当接口被抽象为ISwitchableDevice接口/抽象类时,所有权将转移到客户端或共享层.因此,对接口的更改不能直接由服务器需求驱动,可以在不更改接口的情况下对Lamp类(由服务器拥有)进行任何更改.如果需要更改ISwitchableDevice接口,那么这将由客户端或共享层的需求驱动.