Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the Dependency-Inversion Principal (DIP) reduce the need to make changes to depending modules when their dependencies change?

I recently read about the Dependency-Inversion Principal in Robert.C.Martin's excellent book Agile Principals, Patterns and Practices in C#. However there is one aspect of this principal that I feel I don't fully understand.

Robert explains that when high-level modules depend on lower level modules, changes in the lower level modules can cause the higher-level modules to change also. He demonstrates this with the following example:

public class Button
{
   private Lamp lamp;
   public void Poll(){
      if(/*some condition*/)
         Lamp.TurnOn();
   }
}

About this code Robert says "The Button class depends directly on Lamp class. This dependency implies that Button will be affected by changes to Lamp."

As I see it there are two possible kinds of change that we might make to the Lamp class:

1) We may want to change the internal implementation of the class but without affecting the public interface.

2) We may decide to change the public interface to say pass a parameter to the TurnOn method.

What I don't understand is that in the first case why would our changes cause a change to the Button class? The public interface to Lamp has not changed so why would Button need to change?

In the second case I can see that this would require us to change Button. But in this case how would depending on an abstraction change this? Surely if I have a valid reason to change the interface to Lamp then I would also be changing the interface in the abstraction that Lamp and Button depend on. In this case then I have to change Button anyway as the abstraction it depends on has changed.

I realise that there are other benefits to DIP such as re-usability of higher level modules, ownership of interfaces by higher level modules and ability to choose implementations of dependencies at runtime, however I'm struggling to understand how DIP reduces the need for depending modules to change when the interface to a lower level module changes and/or why internal changes in a dependant module may cause change in higher level modules.

like image 610
John Avatar asked Nov 14 '22 01:11

John


1 Answers

I believe the important difference that DIP brings into this example is ownership of the interface. Particularly which layer owns the interface, where the Button is the client and the Lamp is the server.

In the dependency to the concrete class Lamp, the interface (.TurnOn()) is owned by the Lamp class (server). Therefore a decision can be made to change the .TurnOn() method based solely on the needs of the server as it owns the method, and this will require a subsequent change to the Button class (client).

When the interface is abstracted to an ISwitchableDevice Interface/Abstract class, the ownership is transfered to the client or a shared layer. Therefore a change to the interface cannot be driven directly by servers needs, any changes to the Lamp class (owned by the server) can be made without changing the interface. And if changes to the ISwitchableDevice Interface are required then this will be driven by the needs of the client or shared layer.

like image 133
Richard Oliver Avatar answered Dec 19 '22 03:12

Richard Oliver