3

Before asking this question I like to say that this question in stackoverflow is very similar to my question but still the concept is not clear very confusing.

I am trying to understand the dependency inversion principle but I could not able to understand it completely?

The below are two point which DIP says

A. High-level modules should not depend on low-level modules. Both should depend on abstractions. B. Abstractions should not depend on details. Details should depend on abstractions.

I can able to grasp the first point but I cannot able to get the second point, its look like both are same. After lots of search in stackoverflow & other sites I can able to understand both are trying to say different thing but I could not able to get it.

Let’s consider an example:

Let’s consider SalaryCalculator class [High level module] which is used to calculate the salary of employee. Which uses BonusCalculator [High level module] to calculate the salary as shown below. Since SalaryCalculator is using BonusCalculator it’s violating the first point of “High-level modules should not depend on low-level modules. Both should depend on abstractions”.

enter image description here

So we introduced abstraction between both as shown below:

enter image description here

Here details [Low & High level Modules] is dependent on Abstraction & abstraction is not dependent on details. So in DIP what that second point is trying to tell? If both are same why it is made as two points?

If some one gives me an code example , that will be very useful.

Stanislav Kralin
  • 11,070
  • 4
  • 35
  • 58
vicky
  • 2,119
  • 4
  • 18
  • 32

2 Answers2

5

This question really gets at the heart of why OOP is useful, and why abstractions are so fundamental to computer science. Basically, we use abstractions when we want to hide complexity (details) from the users of our software.

For instance, if I am writing the Bonus Calculator, and you are writing the Salary Calculator, I want to be able to make adjustments to my code without breaking your application.

This requires that we both agree on a particular abstraction that will never change. I provide you with methods to access the functionality of my code, and I promise you that calling these methods will always give you the same results, even though the "details" of my implementation are free to change over time.

So going back to the original questions:

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

  • By "abstracting away" the functionality contained in the low level module (Bonus Calculator), you should be free to switch to someone else's bonus calculator relatively easy if you find my service to be garbage.
  • This is because you have protected yourself from the "details" of my code via the abstraction.

B. Abstractions should not depend on details. Details should depend on abstractions.

  • If your abstraction was dependent on the details of my code, then you would have to rewrite everything to switch to a new bonus calculator! That would defeat the purpose.

Code example (javascript):

  • Say we have an abstraction called "sum" that simply calculates the sum of two numbers. You are the consumer of this function, and want to use it like so: sum(2,2) = 4.
  • Now say there are two different modules (functions) that calculate the sum.

    1. function sum(a, b) { return a + b }
    2. function sum(b, a) { return b + a }
  • Obviously these functions are exactly the same, but imagine if this was a complex computation with many different ways of accomplishing the result, and each with a very different runtime performance. You would be free to test which function works better for you, while using the same interface: just calling sum(). The abstraction does not depend on details.

  • By making this so, your high level module is also no longer dependent on the low level module, since you are free to try a different low level module with relative ease.

Sorry this answer is a little messy. Hope this helps!

  • I trying to understand the difference, can you please make it little bit clear? – vicky Oct 17 '18 at 15:25
  • Maybe it will help if you don't think of "details" as the modules, but rather the code that lives within each module. In this model, "details" are the lowest level possible. "Details" are the actual code that is run, independent of what results from running the code. Very confusing but I think it will eventually "click." – Collin Klippel Oct 17 '18 at 16:04
5

Let's break that part B down further.

Abstractions should not depend on details. This can mean that your interface declaration (your abstraction) should avoid including concrete types. Think of the difference between distance(int X1, int Y1, int X2, int Y2) and distance(Point A, Point B). What if you have coordinates measured in floating point, or lat/lon, or polar coordinate systems? What if you change to a 3D space? You'll have to reimplement every routine that uses your distance function.

Details should depend on abstractions. As far as is practical, continue to use an abstraction layer to avoid dependencies on concrete types.

It's all about minimizing the impact of change. The less your code depends on other things, the more it enables that other code to change.

John Deters
  • 4,295
  • 25
  • 41