8

Most readers will be familiar with Bob Martin's famous dependency inversion principle, which states

  1. High-level modules should not depend on low-level modules. Both should depend on abstractions

  2. Abstractions should not depend upon details. Details should depend upon abstractions

I believe I understand it all pretty well, except for the first sentence in the second line - "Abstractions should not depend upon details". What does this mean exactly? What would be a simple example of an abstraction being dependent upon a detail?

1
  • 1
    The definition of "abstraction" and "detail" should clarify this. What part of the definition of "abstraction" confuses you? Perhaps you could update the question to explain why the words are confusing. We're not you, so we don't know what part of this confuses you.
    – S.Lott
    Apr 4 '11 at 15:13
14

What he's saying here is that you should avoid a scenario where a base class takes a dependency to meet the need of a descendant. Let's look at the case of a Switch and its descendant the TimedSwitch. The TimedSwitch is a Switch that resets itself after a certain amount of time. We have the TimedObject class already so it would make sense for TimedSwitch to derive from it...however TimedSwitch already derives from Switch. So in order to meet the needs of the TimedSwitch, Switch will inherit from TimedObject even though it doesn't need that functionality itself.

The Switch (abstraction) is dependent on the details of TimedSwitch. To fix this violation of the DIP, we have TimedSwitch implement ITimedObject and delegate to a contained TimedObject class (prefer composition over inheritance).

Another more generic example is the layered approach. The higher level layers are abstractions and in most cases they depend on the details. DIP says that instead, the lower layers should conform to an interface which they both take dependency on. Thus the dependency is inverted from Higher Layer depending on lower layer to both layers depending on an interface.

2
  • So where is the inversion in the layers example? I can only see new abstraction introduced with additional dependency on it. What exactly is inverted?
    – ᄂ ᄀ
    May 5 '13 at 12:33
  • Unless I misread, the answer pivots on implementation-inheritance being singular. Jun 7 at 15:53
2

The controller module uses the ControllableThing abstraction (interface) to control a Thing module.

A bad design would have the ControllableThing interface exposing the number of LED lights in the FizzBuzz corporation Thing the project was written for originally. setLed1(boolen state) setLed2(boolen state) setLed3(boolen state) setLed4(boolen state)

that sort of thing...

So now, both modules will break when we go to control a Nazbatag intelligent rabbit module.

The DI principle is really about getting the dependancy graph for the system to have very short paths from modules to interfaces.

When the abstractions are done right the systems won't break next week.

Judgement should be used, because the temptation to make generic interfaces leads things that look like SOAP and the Unix device model. A meta system can help if you're architecting systems of systems. There is a design force here pushing towards dynamic languages and call-time binding. It's not necessary or helpful to give in to it all the time.

1
  • +1 Great footnote about using the right tool for the job.
    – jv42
    Apr 4 '11 at 8:27
0

Abstraction means to "forget" or "surpress" details and only use what you need. I find the best way to word abstraction is taken from Ole John Dahl in Structured Programming (https://dl.acm.org/doi/book/10.5555/1243380 section 3). He says something along the lines of "abstract away details that are too far removed and concentrate on the details that are most related to your problem".

So he's saying, don't make your abstractions based on details that you are supposed to be abstracting away. Here's an example:

class String
{
public:
    char characters[32];
};

Applying what he is saying here, the abstraction String shouldn't depend on the details of how its implemented. Or worded differently - the users of string should not depend on the details that are too far removed on what they're using the string for. A user of string doesn't usually care about the computer representation, but cares about what can be done to it.

Here is the String abstraction properly abstracted:

class String
{
public:
    void Concat(String* other_string);
    void Append(char c);
    int Length();
    
private: /* Private here, this is suppressing the details */
    char characters[32];
};

Note how the "details" being the character array is now hidden (or surpressed, abstracted away) and the users of the String class no longer depend on the details.

This book has an amazing explanation of abstraction. Highly recommend skimming it to see how simple abstraction (both procedural and data abstraction) is.

https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-4.html#%_toc_start

https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-9.html#%_chap_1 https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-14.html#%_sec_2.1 https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-17.html#%_sec_2.4.1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.