3

I'm reading the book "Agile Software Development, Principles, Patterns, and Practices" by Robert C. Martin.

When he talks about the Dependency Inversion Principle he gives the following example of a DIP violation:

DIP Violation

This seems very clear to me, as the higher-level object Button is depending on a lower-level object Lamp.

The solution he comes with is:

Solution

He creates an interface so that way Button is no longer depending on the object Lamp.

The theory seems really clear to me, however I can't wrap my head around using the principle in real-life projects.

  • Who is going to determine what classes (that implement SwitchableDevice) need to be called?

  • Who tells Button what devices he need to turn on/off?

  • How do you tell an object that uses something abstract which concrete things it needs to use? (Please correct me if this question is completely wrong)

If anything is unclear about my question, please let me know, I'll be glad to clarify things for you.

2

3 Answers 3

5
  • Who is going to determine what classes (that implement SwitchableDevice) need to be called?
  • Who tells Button what devices he need to turn on/off?
  • How do you tell an object that uses something abstract which concrete things it needs to use? (Please correct me if this question is completely wrong)

The term often used is "wiring", which refers to the activity of connecting decoupled classes together. It typically involves connecting abstract interfaces to concrete classes, and managing the injection of each concrete instance when the application starts.

Wiring commonly happens in a top-level part of a program near the entry point known as the Composition Root. That might be a method called by main() or it might even be main() itself. (This isn't always the case though; for example, ASP.NET handles wiring on a per-HTTP-request basis, so this is more about typical use cases than hard/fast rules)

The analogy could be similar to wiring an electronic system which has a lot of small components that need to be connected together in order to create a working system; e.g. wiring up the many components of a robot which has all kinds of moving parts and circuit boards.

The motivation for this approach to software construction is to be able to treat an application like a set of independent, disconnected, cohesive "building blocks" which are fused together at the top-level of the application in order to make something which works.

Each building block of an application may represent (or take responsibility for) an aspect of that application's functionality. For example, an object repository, a factory, an interface to a network messaging system, a business rules engine, an event processing system, an interface to an external API, a "main menu" UI, etc.

Splitting classes/components out like this alllows each component to be developed on its own, with its own independent development lifecycle, its own unit tests, and its own identity; agnostic to other components of the application.

Many applications have some kind of shell or controller type component which hosts the user interface (GUI app) or main thread (service/console app) which bridges the 'gap' between the UI/UX and the rest of the app components.

Breaking an application's behaviour into many smaller classes often results in a number of single instance, (mostly) stateless objects whose lifetime matches that of the application, but which still need to interact with each other; these types of classes are ideal candidates for Dependency Injection.

There there are plenty of cases where application behaviour might come from throwaway, short-lived, stateful objects too - sometimes these are also injected, but they can be a little more awkward to deal with, so these sometimes get encapsulated inside other patterns such as Strategy, Factory, etc.

Some very simple c# code for Bob Martin's example might look like:

static void Main(string[] args)
{
    ISwitchableDevice switchableDevice = new Lamp();
    var button = new Button(switchableDevice);
    // TODO - wiring for other classes which use button and switchableDevice
}

I don't think Uncle Bob's example on it's own is really sufficient to demonstrate DI/IoC in a real application - it only demonstrates constructor injection as an alternative to object ownership.

Here's a very contrived potential example of a background service whose responsibility is to listen for network control messages and toggle a lamp on and off:

static void Main(string[] args)
{
    ISwitchableDevice switchableDevice = new Lamp();
    var button = new Button(switchableDevice);
    var messageListener = new NetworkMessageListener();
    var serviceController = new ServiceController(messageListener, button);

    // The wiring is done, now start the main thread and block...
    serviceController.StartMainThread();
    Thread.Wait();
}

In the above example, I'm assuming that the app is made up of 4 different classes, all of which are shown in the Main method; those classes don't need to call new to create other classes because Main() (the composition root) uses poor-man's DI to create the various components of the application and wire them all up together.

You can assume that each concrete class' constructor accepts its dependencies using some interface, and that none of those classes actually know about each other.

The above pattern scales out very well - when a new component needs to be added to the application, it's added into the composition root, and the composition root handles its wiring/dependencies (and/or injects it into one of the existing components if necessary).

4
  • 1
    This is exactly the answer I was looking for. I completely understand what should be done now, the wiring example really clarifies a lot. I develop a lot of OO PHP using the Laravel (laravel.com) Framework. I am not sure if you are familiar with that, but in Laravel you have a IoC container in which you bind the abstracts to concretes (and resolve them from the container). Do you have similar IoC containers in C++ / C# etc. I'm starting to dig more into C++ now as I want to greatly increase my programming knowledge (especially of the more low-level programming languages). Apr 13, 2017 at 20:47
  • @MelvinKoopmans I'm not personally familiar with PHP/Laravel; there are dozens of IoC containers in C# though (to name a few popular ones: Unity, StructureMap, Windsor, Ninject..). C++ has fewer well-supported IoC tools, although you can still use poor-man's DI. However C++ has a lot of language features which open up many strange design possibilities which you'll not find in any other languages, for example Policy-based Design or Template Metaprogramming Apr 13, 2017 at 22:17
  • @downvoter please suggest how the answer could be improved, as suggestions help improve the quality on this site for everybody. Thanks! Apr 13, 2017 at 22:38
  • Thanks Ben, I will take a look at those other design possibilities in C++. Seems interesting Apr 14, 2017 at 5:29
0

There are two parts to every programming project:

  • the fun parts - this is where you program the logic, where you make injectable dependencies using dependency injection,
  • the necessary parts - where the object graph1 is created.

In your case you've got the fun parts in turning on and off some device - you define a logic that when a button is toggled a device either turns on or off. What you are missing is the necessary part, telling which button is actually going to be assigned to which device.

Who?

Well this is always going to be you, as a programmer. You are providing the wiring logic, you are telling, how the Button object is being instantiated. You can either forcefully instantiate it directly in the code, or give the users some freedom. Eg. by having a List of SwitchableDevice objects. And when a user selects a device in this list, you construct a button by injecting to it the SwitchableDevice instance at the selected index from the list.

How?

This depends on what an actual class is.

If it's a service supposed to act as a singleton, then you are likely to use some dependency injection framework, such as Spring, Guice, Ninject, PicoContainer.NET,... where you configure the framework to provide you a concrete instance when an interface is requested by another class. This usually happens when you know that once an application bootstraps you will only ever need one implementation of some interface.

If on the other hand you need runtime switching (give users some configuration freedom), you will ned to provide some king of factory/strategy pattern combination, where you will have a method returning you a specific instance of an interface, most likely based on some flag - such as type id.

public SwitchableDevice get(SwitchableDevice.Types type)
{
    switch (type) {
        case SwitchableDevice.Types.Radio:
            return new Radio();
        case SwitchableDevice.Types.Light:
            return new Light();
        case SwitchableDevice.Types.Computer:
            return new Computer();
        default:
            throw new UnimplementedException("Unsupported type.");
    }
}

This is very simplified form, in real-life it's likely a Radio, a Light and/or a Computer object will already exist somewhere else, be present within a memory, and when a user chooses a specific device you fetch it, knowing it implements the SwitchableDevice interface and attach it to a button of your choice.


1 How classes are wired (instantiated) together - which instances are actually injected.

0

The actual communication could be done via an observer pattern. Let's say I have switchable device controller that maintains a list of objects that implement ISwitchableDevice. It also has subscribed to the click event of the button.

So, when the button is clicked (event raised), the controller calls each of the objects that it is currently maintaining turn on/off method.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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