5

Often DIP is known as the Hollywood principle: "Don't call us, we'll call you.".

But doesn't always higher level module calls lower level module, whether there is dependency inversion or not?

Then why is DIP called the Hollywood principle?

Am I missing something? Thanks!

8

A common way of writing OO code is to to have code such as:

void SomeMethod()
{
    SomeClass x = new SomeClass(params...);
    ...
}

or code such as:

void SomeMethod()
{
    SomeClass x = SomeStaticLocator.GetSomeClass();
    ...
}

In both cases, the code is obtaining other parts of the system by "asking" for them.

With dependency injection/dependency inversion, the opposite (inverse) approach is taken:

void SomeMethod(SomeClass x)
{
    ...
}

Rather than the method asking for its dependencies, it is told what they are. This helps to reduce coupling within the system and makes testing a lot simpler. Further improvements are to then design to interfaces, rather than concrete types to further decouple parts of the system:

void SomeMethod(ISomeClass x)
{
    ...
}

Because the method/class is being supplied its dependencies, rather than it needing to request them itself, the terms "tell; don't ask" and "don't call us, we'll call you" are often used to sum up the behaviour of DI.

  • I think your DI = Dependency Injection? Dependency injection is one of the ways to achieve dependency inversion. It is not the whole story. Please correct if I am wrong. – q126y Dec 17 '15 at 11:49
  • This is sometimes known as the Hollywood principle: "Don't call us, we'll call you.' The lower-level modules provide the implementation for interfaces that are declared within, and called by, the upper-level modules. - Uncle Bob – q126y Dec 17 '15 at 11:52
  • @q126y, "dependency inversion" is one of those odd terms that seems to have no clear definition. We have dependency injection (DI), which I describe here, and Inversion of Control (Ioc), which uses a framework to inject dependencies both into the caller and the callee. Then we have dependency inversion. Is this DI? Is it IoC? Either way, "tell, don't ask" describes DI. IoC takesit a step further to something like "we'll tell you what to tell", which isn't quite so snappy. Am I wrong with this, and thus is my answer wrong? – David Arno Dec 17 '15 at 12:01
  • @q126y, to my mind, after reading eg martinfowler.com/articles/injection.html and stackoverflow.com/questions/3912504/…, there is no clear definition for any of the three terms. The terms overlap, people use them differently and eg Martin Fowler appears (from my reading of his article) to take the view that IoC and Dependency Inversion are unhelpful fluffy terms and that we might as well call the whole lot DI. :) – David Arno Dec 17 '15 at 12:08
  • your "tell, don't ask" reference, helped me to infer what uncle Bob really meant w.r.t. DIP. The higher level module owns its service interface, it tells what interface it needs and not asks, as is generally the case. "Notice that the inversion here is not just one of dependencies, it is also one of interface ownership. We often think of utility libraries as owning their own interfaces. But when the DIP is applied, we find that the clients tend to own the abstract interfaces and that their servers derive from them. This is sometimes known as the Hollywood principle" - Uncle Bob – q126y Dec 17 '15 at 13:28
3

Dependency inversion principle is a fancy name for "coding to abstraction, rather than concrete implementation".

In procedural programming, the Holywood principle is not applicable. The flow of the application goes (mostly) from the top to bottom with possible loops, containing switches and conditionals, which decide what is the next action.

This means, the user has no control over the procedure execution, because it is predetermined by the software programmer.

DIP means, you do not know what exactly is going to be executed until the caller, usually the user of you application, wants to use (for example) some service.

Consider the following example:

interface FancyStuff
{
    int GiveMeNumber();
    bool ProcessNumber(int number);
}

You have an interface which institutes a contract that by calling the GiveMeNumber() method you will have an int to work with and also allowing you to use the ProcessNumber() method returning boolean and taking in an int as a parameter.

Somewhere in your app, perhaps the service layer, you can have a class depending on this interface.

class FancyStuffService
{
    private FancyStuff fancyStuff;

    public FancyStuffService(FancyStuff fancyStuff)
    {
        this.fancyStuff = fancyStuff;
    }

    public bool FancyOperation()
    {
        var number = this.fancyStuff.GiveMeNumber();
        ++number;
        return this.fancyStuff.ProcessNumber(number);
    }
}

Notice, how you are using some methods, but you do not have any implementation. The class FancyStuffService has no idea, what the implementations for the methods GiveMeNumber() and ProcessNumber() look like, but it knows, which return values it may expect and what to pass to them.

Naturally, without an implementation, the interface is pretty useless, so you implement two versions of the FancyStuff interface to provide the logic.

class FancyStuffImplOne : FancyStuff
{
    int GiveMeNumber()
    {
        return 5;
    }

    bool ProcessNumber(int number)
    {
        return number != 0;
    }
}

class FancyStuffImplTwo : FancyStuff
{
    int GiveMeNumber()
    {
        return 42;
    }

    bool ProcessNumber(int number)
    {
        return number < 15;
    }
}

You have an implementation of your FancyStuff interface, you have a FancyStuffService which uses the interface, and you have to wire it all together. But how?

In your factory pile, of course. That is where all the new operators in your application are, meaning it is a place where the objects are constructed.

class FancyStuffServiceFactory
{
    private FancyStuff ObtainFancyStuffImplementation(int id)
    {
        switch (id)
        {
            case 1:
                return new FancyStuffImplOne();
            case 2:
                return new FancyStuffImplTwo();
            default:
                throw new RuntimException("Undefined fancy stuff ID.");
        }
    }

    public FancyStuffService BuildFancyStuffService(int fancyStuffId)
    {
        var fancyStuff = this.ObtainFancyStuffImplementation(fancyStuffId);
        return new FancyStuffService(fancyStuff);
    }
}

And the variable fancyStuffId is exactly what you want. The integer could be populated during the runtime with an input from the user, perhaps via a selectbox, or any other method.

Only after a user inserts or selects some number, the factory is called, passing the user's input into the factory, which in return creates a FancyStuffService for the user to use. Once that is done, there can be an event mapped to call the FancyOperation() method of the FancyStuffService class.

Also notice, how you do not know which implementation of the FancyStuff will be chosen until you really need it. That is the holywood principle at work.


Note, that DIP is directly tied to dependency injection and cannot work without it. Which is good, considering dependency injection prevents global states and static methods and leads to code which is testable.

2

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.

A long time ago, in a galaxy far, far away, there existed two droids: a supervisor droid (model S-100) who was programmed to routinely issue requests to a cleaner droid (model C-100) to clean a room. The cleaner droid was programmed to grab a broom, use its wheels to go to the appropriate location, and begin cleaning the dirty room.

enter image description here

This was all fine and dandy, until the invention of a new cleaning device for certain situations known as a mop.

Since the C-100 was not programmed to use a mop, a new model of cleaning droid had to be invented that could utilize both a broom and a mop, known as C-101.

However, since the S-100 was not programmed to communicate with anything but a C-100, a new model of the supervisor, S-101, also had to be created to account for C-101.

enter image description here

... and this lead to order in the universe...

... until the invention of a new cleaning device known to the mystics as the dust mop.

At this point, the designers were getting fed up. To create a new C-102 model here to handle this new and alien cleaning device would likewise require a new S-102 model.

To solve this problem, the elders convened and decided that all of these cleaning devices should be standardized with an abstract cleaning interface.

enter image description here

This abstract cleaning interface allowed the new C-102 to work with any compatible cleaning device through this common interface. Unfortunately this still required a new S-102 to be designed to interface with C-102, but the designers were confident that no new cleaning devices introduced hereafter would require a new supervisor model.

enter image description here

... and order was once again restored in the galaxy...

... until the invention of a new transportation device known as legs which allowed droids to work in more complex environments.

At this point, the designers of the S and C series of droids threw themselves off a cliff.

The elders convened and brought in a new design team to solve the problem. The new design team recognized that in order to avoid yet further and further modifications to the S model, the C cleaning droid model also needed an abstract interface through with the supervisor model would communicate. In addition, they realized a similar treatment was required for an abstract transportation interface.

enter image description here

... and cleanliness spread through the universe like a spring breeze (except, of course, that spring time did not exist in this galaxy)...

... until the invention of the hoverboard which made legs and wheels obsolete.

This caused the new design team to commit ritualistic light saber seppuku. The elders then brought yet another design team to replace the former one.

At this point, design team C realized that even though the supervisor droid did not have to change, the cleaning droid still needed programming to be aware of all the various types of cleaning and transport devices available for it to use (shown in red in above).

They also realized that the supervisor droid, who was merely programmed to routinely issue requests to clean rooms, was actually much easier to change than the cleaner droid, and had far less general applicability than a cleaner droid.

And thus, the designers decided to make cleaner droids accept requests to use any compatible cleaner device and any compatible transport device from a supervisor droid.

They also decided to use blue for abstract interfaces in their schematics, after realizing that they like blue.

enter image description here

... and thus was born the basic idea and primitive form of both dependency inversion and dependency injection, which would get further and further embellished in the future.

A curious thing happened with this new design. Instead of the cleaner robot being programmed to use these low-level cleaning and transportation devices directly, it was now being told what type of cleaning and transportation devices to use. Using its very limited A.I., the new prototype model of cleaning droid attempted to ask the designers what cleaning devices it should use now that it is no longer programmed to use specific ones. "Don't worry about it, your model will be told what to use when needed, but rest assured that a compatible cleaning and transportation device conforming to your abstract requirements will be supplied," said the designers.

A random passer-by then looked at this schematic and scribbled something obscure about efferent and afferent couplings yielding an instability metric while mumbling something cryptic about the ease at which packages can be modified.

enter image description here

The galaxy rejoiced with their new and flexible design until the designers realized that the supervisor droid was doing too much, and the elders realized that the designers and the factories they worked in should be included in the schematic.

The End

  • The analogy looks good! But I think we don't really see the role of the supervisor. Is it from you ? (It's an old post but I try) – Etsitpab Nioliv Jan 17 '17 at 16:47
0

Inversion of Control

As demonstrated by @davidarno, you construct bottom up by instantiating the smaller bits first then passing that to the object's constructor it belongs in, and so on. In other words the construction of a composite has been inverted.

Also see this example of Object Oriented Dice


IOC enables Dependency Injection

Now we are passing the needed object - the dependency - via the constructor. Vola. Dependency Injection. Passing parameters IS dependency injection. But the larger point is now we can inject different objects; and there is further flexibility by specifying base types and interfaces.


The Hollywood Principle

Quoting from Head First Design Patterns

The Hollywork principle gives us a way to prevent "dependency rot." Dependency rot happens when you have high-level components depending on low-level components depending on high-level components depending on sideways components depending on lo-level components, and so on.

With the Hollyworod Principle, we allow low-level components to hook themselves into a system, but the high-level components determine when they are needed, and how. In other words the high-level components give the low-level components a "don't call us, we'll call you" treatment.


The Clean Architecture by Bob Martin

The Hollywood Principle can be seen at work in the article

enter image description here

The overriding rule that makes this architecture work is The Dependency Rule. This rule says that source code dependencies can only point inwards.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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