1

After looking up on the top most of the answers I've found is this:

  • High level modules should not depend upon low-level modules. Both should depend upon abstractions.
  • Abstractions should never depend upon details. Details should depend upon abstractions.

My understanding on this is that this kind of design violates it? because the class Car depends on the lower level class Engine?

public class Car {
    private Engine engine;

    public void run() {
        engine.start()
       // do other stuff
    }
}

public class Engine {
    public void start() {
         // do stuff that will start engine
    }
}

If it does violate it, whats the solution? I can't think of an alternative.

Im also having a hard time understanding the second part "Abstractions should never depend upon details. Details should depend upon abstractions."

jantristanmilan
  • 4,188
  • 14
  • 53
  • 69

3 Answers3

2

Below link explains the concept of dependency inversion well: http://www.oodesign.com/dependency-inversion-principle.html

Basically, it boils down to complex classes depending on behaviour of simple classes, rather than the classes themselves. In your example, the below would be a good implementation of dependency inversion:

interface Movable {
    public void start();
    public void throttleUp();
    public void throttleDown();
    //etc..
}

class Engine implements Movable {
    public void start() {
        //code
    }
    //implement other methods
}

class Car {
    Movable engine;

    public void setEngine(Movable engine) {
        this.engine = engine;
    }

    public void run() {
        engine.start();
        //code...
    }
}

In future you can create different types of engines like petrol, diesel, steam, electric. But as long as they implement Movable, your Car will not change since it is decoupled.

kaykay
  • 556
  • 2
  • 7
1

You need to understand the difference between runtime dependency and code dependency. Car will always have a runtime dependency on your Engine implementation details, because the control flow will move from the Car to the Engine.

However, Dependency Inversion is about the source code dependencies. You could make Engine an interface or abstract class, and different subclasses could provide their own start() implementation (polymorphism). This way, your Car would depend only on the Engine abstraction (on the source code level), but not on the details of the various start() implementations. You could add new engines to the system after Car was written, compiled and deployed.

Also note that these principles are more like recommendations, not "always/never" rules. Use your own judgements.

lbalazscs
  • 17,474
  • 7
  • 42
  • 50
  • A note regarding the "rules" part of your reply: `Dependency Inversion` is part of the SOLID paradigms, so if you want write SOLID code then you must follow those rules. – Cristik Apr 23 '15 at 20:45
  • 1
    @Cristik Well, I don't want to write "SOLID code". I want to write good code, and while "SOLID" principles are good guidelines, they sometimes contradict other good guidelines such as KISS ans YAGNI. – lbalazscs Apr 23 '15 at 20:57
  • I don't think SOLID, KISS, and YAGNI are mutually exclusive, they target different aspects. SOLID takes care of robust code, YAGNI targets bloated but correct code, while KISS takes care of code that can get complex. You can respect all three (although I must say I find it difficult to follow only one of this :) – Cristik Apr 23 '15 at 21:01
  • 1
    @Cristik You should read the answers to this question before you start defining an interface for every class: http://programmers.stackexchange.com/questions/159813/do-i-need-to-use-an-interface-when-only-one-class-will-ever-implement-it – lbalazscs Apr 23 '15 at 21:36
  • I did not say I will define an interface for every class :) – Cristik Apr 23 '15 at 21:42
  • @Cristik Well, if you intend to apply dependency inversion religiously, in an "always/never" manner, then you *should* define an interface for every class. But now I see that you don't even understand dependency inversion correctly. Details under your answer. – lbalazscs Apr 23 '15 at 22:06
  • Dude, I was explaining a part of the `Dependency Inversion` principle, I wasn't advocating towards any of the things we're discussing here. – Cristik Apr 23 '15 at 22:14
  • @Cristik Yes, I see now. I thought that you are advocating these things when I thought that you understand the dependency inversion principle. Details under your answer. – lbalazscs Apr 23 '15 at 22:30
0

Let me rephrase all that is already there in your post and see if it makes sense

  1. It is perfectly alright for Car to be dependent on the interface of Engine like in your case (as long as the Engine is injected).
  2. High level module like Car should not depend on low level implementation details - say a particular subclass of Engine e.g. JetEngine but it is alright for it to depend on the interface Engine
  3. Abstractions like Engine should not depend on any particular implementation (say a subclass Nut, Bolt or Engine again).
Om Deshmane
  • 808
  • 6
  • 11