65.9K
CodeProject is changing. Read more.
Home

Dependency Inversion principle (DIP)

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0 vote)

Jul 23, 2012

CPOL
viewsIcon

9120

Depend explicitly, require explicitly, but only require what you really need.

SOLID principles:

Depend explicitly, require explicitly, but only require what you really need.

Consider an example (not for production, illustrative purposes only):

public class ConsoleLogger {
  public static void log(String text)  {...}
}

public class SomethingDoer {
  public void doSomething() {
    // I won't show you the code      
  }
}

Is there a connection between SomethingDoer and Logger? You'll never know unless you have a code for SomethingDoer. OK, I'll show you:

public class SomethingDoer {
  public void doSomething() {
    ConsoleLogger.log(new Date().toString());
  }
}

This may not look that bad as long as you have the code. But what if this SomethingDoer is in a 3rd-party library and it sends some stuff to the console while you don't want it? The solution is to explicitly say: "SomethingDoer depends on Logger". Here is a possible solution:

public class ConsoleLogger {
  public void log(String text)  {...}
}

public class SomethingDoer {
  private final ConsoleLogger logger;

  public SomethingDoer(ConsoleLogger logger) {
    this.logger = logger;
  }

  public void doSomething() {
    logger.log(new Date().toString());
  }
}

Logger logger = new Logger();
SomethingDoer somethingDoer = new SomethingDoer(logger);

In this code, you just can't make an instance of SomethingDoer without giving it an instance of Logger. But still, what should we do in case we don't want any output at all? SomethingDoer doesn't basically require any particular logger, it requires something that IS a logger, but no further details are required. So, here's the next step:

public interface Logger {
  void log(String text);
}

public class ConsoleLogger implements Logger {
  public void log(String text) {...}
}

public class NullLogger implements Logger {
  public void log(String text) { /* do nothing here */ }
}

public class SomethingDoer {
  private final Logger logger;

  public SomethingDoer(Logger logger) {
    this.logger = logger;
  }

  public void doSomething() {
    logger.log(new Date().toString());
  }
}

// if we want to enable output:
Logger logger = new ConsoleLogger();
SomethingDoer somethingDoer = new SomethingDoer(logger);
somethingDoer.doSomething(); // got output

// if we want to disable output:
Logger logger = new NullLogger();
SomethingDoer somethingDoer = new SomethingDoer(logger);
somethingDoer.doSomething(); // no output

In future posts, I'm going to cover this topic in more detail.