Abstractions should not depend upon details. Details should depend upon abstractions?
Asked Answered
A

4

51

In past couple of days, I have read about quite a lot about dependency injection/inversion of control/inversion of dependency. I think that, now my understanding of the concept is much better. But I still don't get the following from wikipedia:

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

I understand the part of High-level modules should not depend on low-level modules. But, I am confused about abstractions and details.Can someone please simplify them for me. Thanks.

Asuncion answered 10/11, 2009 at 18:9 Comment(0)
T
87

It means that if the details change they should not affect the abstraction. The abstraction is the way clients view an object. Exactly what goes on inside the object is not important. Lets take a car for example, the pedals and steering wheel and gear lever are abstractions of what happens inside the engine. They do not depend on the details though because if someone changes my old engine for a new one I should still be able to drive the car without knowing that the engine changed.

The details on the other hand MUST conform to what the abstraction says. I would not want to implement an engine that suddenly causes the brakes to double the speed of the car. I can re-implement brakes any way I want as long as externally they behave the same way.

Tusche answered 10/11, 2009 at 18:16 Comment(3)
I like the OP had trouble understanding this concept - great succinct and clear answer thanks.Syllabize
best expanationEsophagitis
This is an excellent example.Philosophy
D
3

An interesting case where an abstraction depends on details is when you define an interface that inherits from IDisposable. Take a look at the following abstraction:

public interface ICustomerRepository : IDisposable
{
    Customer GetById(Guid id);
    Customer[] GetAll();
}

Note: IDisposable is an interface specific for .NET, but you can easily imagine your interface containing a Dispose method itself instead of inheriting from such interface.

It might look convenient for the ICustomerRepository to implement IDisposable. This way any caller can dispose the repository and this way the implementation can dispose the connection or unit of work that it uses internally.

The interface however is now written with a certain implementation in mind, since it's not obvious at all that all ICustomerRepository implementations would need to clean up any resources. The interface therefore leaks implementation details and therefore violates the Dependency Inversion Principle.

Divine answered 20/6, 2014 at 14:17 Comment(2)
If you look closely ICustomerRepository, it has been derivative of IDisposable and already has a disposable method in its implementation to clean up resources and hence make it clear that is mandatory in the implementing classes. So it does not seems like violating DIP.Sissified
Hi Ifran, you might have misinterpreted my answer. The point is that the need to clean up resources is an implementation detail. As it is easy to imagine the existence of ICustomerRepository implementations that do not need to cleanup any resources, you can start to see that the Dispose method does not belong on the abstraction, but rather on the implementation. In later years I posted much more about this. See for instance this and this.Divine
H
1

Example of the abstraction and the details: a stream provides an interface to read a token. That's an abstraction.

A stream implementation of the stream is bound to implement the interface defined by the abstraction: that's why it depends on it. If it provides a different interface (one to read 100 characters at a time) it cannot claim to implement the same abstraction.

Habilitate answered 10/11, 2009 at 18:16 Comment(0)
C
1

Think of the work you need to invoke, and how far away that is from where you are currently coding. There is a spectrum there; your position on it represents the amount of work you need to do to invoke that functionality.

Abstractions move that position closer to the code you are writing. For example, if you have to call a web service, you can either 1) write the calling code directly where you need to use it, or 2) put those details behind an abstraction (such as an interface).

In this case, #1 puts you closer to the web service on the spectrum, while #2 keeps you closer to your work. Abstraction can be said to be a measure of how far you have to stretch your mind to comprehend the work you need done.

What this means is that every piece of work can be abstracted so that it is "closer" to the code using it. By having both sides of an operation depend upon abstractions, they both become easier to understand, and neither side has to harbor knowledge of the gap between them - that is the job of the abstraction.

Wow, that was abstract.

Cambria answered 20/11, 2009 at 21:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.