4

For example, I remember most examples of dependency injection I see is something like this:

public interface Fruit{
}

public class FruitBox{
    public Fruit fruit;
    public FruitBox(Fruit fruit){
        this.fruit=fruit;
    }
}

which can supply different types under Fruit from outside. But my question is, if one day, FruitBox needs 1 type only, eg: Orange:

public class FruitBox{
    public Orange orange;
    public FruitStore(Orange orange){
        this.orange=orange;
    }
}

which I can supply different variations of Orange, but not other types, is it called dependency injection? And another case that involves primitive type only:

public class FruitBox{
    public int maxWeight;
    public FruitBox(int maxWeight){
        this.maxWeight=maxWeight;
    }
}

is it still called dependency injection because I can supply different values of maxWeight?

  • Looks like you are mixing "Dependency inversion" and "Dependency injection". Am I right? – Laiv Mar 11 at 13:28
4

If your code does something like:

void Foo() {
    Bar bar = SomethingRemote.getBar();
    ...
}

then you aren't using dependency injection (DI). If your code does something like:

void Foo(Bar bar) {
    ...
}

then you are using DI. In first case, you are using an "ask" approach to obtaining a dependency, ie you are fetching it from some remote place. In the second case, you are using a "tell" approach: you are directly telling, or injecting that dependency. And that is all there is to DI in its most purest form.

Whether that Foo is an instance of a Fruit interface, an Orange instance or a primitive like an integer makes no difference whatsoever to whether a piece of code is asking or being told about that dependency. It's all DI if we are being told.

The reason why most examples of DI will involve interfaces is unrelated to DI itself. Using DI and designing to interfaces are both good programming practices and so someone using one of those good practices is likely to use the other too.

  • 1
    Correct me if I am wrong, but the first type is called the Service locator pattern – andras Mar 11 at 11:52
  • 1
    @andras, I tend to use that term as a generic "ask" mechanism. But some folk like to eg make a distinction between static factories and service locators, so I avoided using it in my answer as I didn't want to distract away from addressing dependency injection. – David Arno Mar 11 at 12:43
  • oh okay, makes sense. I just like to have references for further reading to know there is always a lot more to a certain topic. – andras Mar 11 at 14:03
  • DI and using interfaces is not unrelated at all - the whole point of DI is to enable the use of different dependencies, and implementations of an interface is a major way in which the dependencies can differ. – Michael Borgwardt Mar 12 at 7:47
  • 1
    @MichaelBorgwardt, are you not muddling dependency injection and dependency inversion here (both of course being abbreviated to DI)? The use of interfaces (or other abstractions) is key to dependency inversion. It's orthogonal to dependency injection though in my view. – David Arno Mar 12 at 9:19
1

Let's say you have three classes which inherit each other. I slightly changed the example to make more sense (I don't know specific types of orange):

public class Fruit {}

public class CitrusFruit : Fruit {}

public class Orange : CitrusFruit {}

What you're supposing is that

It's only dependency injection if the injected dependency is of the Fruit type, and that it's not dependency injection if the injected dependency is of the CitrusFruit type.

The short answer is that that is not correct.

A simple way to showcase the point, is that I could apply that same line of thinking, because Fruit really still inherits from object:

It's only dependency injection if the injected dependency is of the object type, and that it's not dependency injection if the injected dependency is of the Citrus type.

Effectively, if that logic were true, then you could never use dependency injection with any class and would be stuck using object types.


At its very core, dependency injection doesn't even require inheritance or interface implementation. By simply passing an object as a method/constructor parameter as opposed to retrieving it internally in the method/constructor, you are injecting it.

However, much of the architectural benefit of dependency injection is lost when you don't use inheritance/implementation, simply because inheritance/implementation gives you a lot of options in terms of how you allow for any viable dependency to be injected where you want it to be.


is it still called dependency injection because I can supply different values of maxWeight?

This is a debatable issue, because people will disagree on the naming.

I am of the opinion that dependency injection is really just a fancy name for using method parameters. E.g. consider the difference between:

public int AddNumbers()
{
    var firstNumber = ReadFromConsole();
    var secondNumber = ReadFromConsole();

    return firstNumber + secondNumber;
}

and

public int AddNumbers(int firstNumber, int secondNumber)
{
    return firstNumber + secondNumber;
}

The second version can be considered to inject the dependencies (i.e. number values). This makes it possible for whoever calls this method to decide which values are provided, as opposed to having the AddNumbers method decide that for itself.

However, some people see dependency injection in a narrower scope, where the name only applies to cases of constructor parameters (not just any method) where you make use of an (automated) DI container.

I don't think there's reason to distinguish one from the other, since they solve the same issue (giving control to the caller) in exactly the same way (parametrisation).

1

Here's my two cents, DI does not mean only using interfaces. We can use interfaces, classes or even primitive types to define the type of dependencies. The two most important aspects of Dependencies Injection, in my opinion, are:

  • Dependencies are injected to the object by several methods (constructors, setters, method parameters). We have the full control of which instances of the dependencies to be used without the need of modifying the class.

  • With the help of Containers, dependencies of a class/method is initiated automatically when required.

Both your examples can be called Dependencies Injection:

  • You can change the input to another instance of the Orange class or child class and you can change your maxWeight argument to another integer without modifying your FruitBox class.

  • With a proper configured Containers, a FruitBox instance can be initialised with all dependencies automatically.

  • When you say "sticking with interfaces", do you mean interface specifically, or any interface (general English) provided by either class inheritance or interface implementation? You might want to clarify that given OP's context of using inheritance. – Flater Mar 11 at 9:12
  • Thank you, @Flater. I edited my answer to clarify it. – Hieu Le Mar 11 at 9:26
1

Yes, it's. All three examples involve dependency injection since whatever FruitBox depends on is being injected regardless of its concreteness or type. I say injected in counterposition of initialising the dependency directly from the FruitBoxitself.

No injection

public FruitBox(){
    this.orange = OrangeFactory.createOrange();
    //or
    this.orange = new Orange();
} 

vs

Injection

public FruitBox(Orange orange){
    this.orange = orange;
} 

Still injection

//... rest of the class
public setOrange(Orange orange){
    this.orange = orange;
} 

Regarding the first example, it goes a little bit further (but not too much) and brings to the picture Dependency Inversion Principle, what comes to say: -Don't depend on concrete components. Rather depend on abstractions-.

public FruitBox(Fruit fruit){
    this.fruit = fruit;
} 

So, if we make FruitBox to depend on the abstraction Fruit, we realise that someone will have to pass (inject) the fruit. The key here lays on two facts. On one side, Fruitbox doesn't care either of the fruit type nor its origin. It just expects a Fruit and only knows about Fruits (cohesion). On the other hand, the dependency relationship between the concrete class (Orange) and its initialization is now somewhere, out of the FruitBox concerns (responsibility).

When to use one or another (or both) techniques depends on the goals. Usually, both techniques work great together because they favour the testability and the extension of the code. No to mention both contribute to the generation of stable abstractions and stable dependencies.

Related links

-1

Dependency injection is usually used to refer to the injection of complex objects into a class via a constructor parameter or (occasionally) by setting a property. The use of primitives is not usually considered dependency injection. A dependency is something that your class is dependent on to operate properly. It doesn't refer to properties of your object.

A good rule of thumb for determining what is or isn't dependency injection is to ask the question "could or would I use a DI container to resolve this constructor parameter". In the case of your oranges, they would be considered DI, as would the fruit. But the maxWeight would not be considered DI, since it is a primitive and you would not use a DI container to inject that value. MaxWeight is not a dependency (even though it might be a property).

  • If you are going to downvote, please provide reasons as to why you have downvoted. Do you disagree with the answer? Was there a factual mistake? – Stephen Mar 13 at 0:54

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.