Dependency Injection Explained with Burgers

Part 1: Fried Burgers

Yumm!

Dependency Injection is often touted as one of the pillars of object-orientated design. But what is it? How do we use it? Can it be explained using burger analogies? Let’s find out.

Suppose I have the class below, called BurgerChef, that uses a frying pan for cooking tasty, but greasy burgers. It has one a constructor, which gets a new frying pan, and it has one method, that uses the frying pan to cook a burger.

public class BurgerChef {
private FryingPan theFryingPan;
public BurgerChef() {
this.theFryingPan = new FryingPan(); // call FryingPan’s constructor
}
public CookedBurger cookBurger(RawBurger burgerToCook) {
CookedBurger aCookedBurger = theFryingPan.cookBurger(burgerToCook);
return aCookedBurger;
}
}

This is the FryingPan class:

public class FryingPan {
public FryingPan (){ //constructor
//get a clean frying pan from the cupboard
}
public CookedBurger cookBurger(RawBurger aRawBurger) {
// Put oil in the pan and heat it up
// Fry the burger in the greasy frying pan
}
}

To use the BurgerChef class we would do:

BurgerChef mike = new BurgerChef();
RawBurger aRawBurger = new RawBurger();
CookedBurger aCookedBurger = mike.cookBurger(aRawBurger);

(For brevity I have omitted the code for the raw and cooked burgers)

Part 2: Chargrilled Burgers

Even better!

Now suppose our facilities are getting upgraded and we are getting a chargrill for healthier and less greasy burgers. We need to change our class to use a chargrill instead of a frying pan. Not a big deal in this case, as BurgerChef is only a small class.

However, imagine if our class was very large and used the frying pan in lots of different places, that would be a real pain to change. Before our class gets that big it would be a good idea to stop this becoming a problem in the future. The way to achieve this is called Dependency Injection.

If we change our class to use an abstraction instead of a frying pan, say a….cooking tool, then we can change the cooking tool without having to change our class at all next time.

First, we should create our abstraction using an interface (you could also use an abstract class):

public interface cookingTool {
public CookedBurger cookBurger(RawBurger theRawBurger);
}

Then we should change our frying pan to implement this interface, to show that it can be used to cook burgers, we can also create the new Chargrill class.

public class FryingPan implements CookingTool {
public FryingPan (){ //constructor
//get a clean frying pan from the cupboard
}
@Override
public CookedBurger cookBurger(RawBurger aRawBurger) {
// Put oil in the pan and heat it up
// Fry the burger in the greasy frying pan
}
}
public class Chargrill implements CookingTool {
public Chargrill (){ //constructor
// Turn on the chargrill and let it heat up
}
@Override
public CookedBurger cookBurger(RawBurger aRawBurger) {
// Cook the burger on the hot chargrill
}
}

Now we have to change our BurgerChef class to use a cookingTool instead of a frying pan:
noteWe are going to use constructor-based dependency injection in this example, the cooking tool is decided when we create a new BurgerChef object.

public class BurgerChef {
private CookingTool theCookingTool; /* can hold any object that implements our CookingTool interface */
public BurgerChef(CookingTool toolToUse) { /* here we set the cooking tool to use when we construct our BurgerChef */
this.theCookingTool = toolToUse;
}
public CookedBurger cookBurger(RawBurger burgerToCook) {
CookedBurger aCookedBurger = theCookingTool.cook(burgerToCook);
returned aCookedBurger;
}
}

Now we can create a BurgerChef object, and can pass any object into the constructor that implements the CookingTool interface.

Chargrill theChargrill = new Chargrill(); //this could easily be a frying pan
BurgerChef mike = new BurgerChef(theChargrill);
RawBurger aRawBurger = new RawBurger();
CookedBurger aCookedBurger = mike.cookBurger(aRawBurger);

We have basically achieved our goal, we no longer have to change our BurgerChef class to change the cooking tool, but we are now choosing the cooking tool in the calling method. This may sometimes be what we want, but another option is to have “injector” classes whose sole responsibility is to select the type of CookingTool. This adheres to SOLID principles (look them up) and is useful if we know our cooking tool is not going to change on the fly.

Our injector class could be:

public class CookingToolInjector() {
public CookingTool getCookingTool() {
return new Chargrill();
}
}

and could be used like so:

CookingToolInjector ourInjector = new CookingToolInjector; /* or make it a static method and you don't need this line */
BurgerChef mike = new BurgerChef(ourInjector.getCookingTool());
RawBurger aRawBurger = new RawBurger();
CookedBurger aCookedBurger = mike.cookBurger(aRawBurger);

Now if we ever upgrade our cooking tool again, to say….. a burger-making robot, then we only have to change our CookingToolInjector class and no other part of our code (unless we want to sack our burger chef). However if our chargrill was second-hand and unreliable, we might want a different solution where we could change our cooking tool during program run-time, I’ll let you consider that, there are many different ways, but setter-based injection could come in handy.

Although I haven’t touched on it here, the main benefit of Dependency Injection is for easy unit testing. It makes it very easy to pass dummy objects into your methods at test-time, so you can test them with reliable results (i.e. use a dummy database).

-Mike Gregory

share this post

Share on twitter
Share on facebook
Share on linkedin
Share on email
 let's have a proper conversation contact us

let's have a proper conversation

more to explore

2021 has been an eventful year!

We’re looking back and reflecting on everything we’ve achieved this year. Thank you to everyone who has worked with us this year. We’ve been fortunate

One person standing in a warehouse, surrounded by professional lights, audio equipment, and cameras. This is part of Creative agency, Colonel Duck's Video Production in Birmingham with BVSC to capture real life stories.

productions

we create and deliver captivating content that audiences engage with.

Two computers next to each other, one showing a web application, created by software agency Colonel Duck, called Pre Enrolment, and the other with software related code

systems

we build and evolve robust platforms that people want to use.

The BBC live streaming one of the Multiple Disadvantage day events, a choir singing, in Birmingham Grand Central Station.

campaign

we design and manage effective campaigns that exceed set targets

info@colonelduck.co.uk
0121 426 3776
Studio 2, Weekin Works
112-116 Park Hill Road
Birmingham
B17 9HD

This site uses cookies: Find out more.