views:

87

answers:

2

I am interested in applying dependency injection to my current project, which makes use of the MVC pattern.

My controllers will call the models and therefore will need to inject the dependencies into the models. To do this, the controller must have the dependencies (such as a database object) in the first place. The controller doesn't need to make use of some of these dependencies (such as the database object), so I feel that it shouldn't be given this dependency. However, it has to have these dependencies if it is to inject them into the model objects.

How can I avoid having dependencies injected into an object just so that it can pass them on? Doing so feels wrong and can result in many dependencies being injected into an object.

Edit: I am using PHP.

+1  A: 

I'm not speaking from PHP experience but you should look into Inversion of Control (IOC) Containers.

This question on StackOverflow talks about IOC Containers for PHP. For a quick overview of some of the other benefits of IOC Containers you should check this question, probably one of my favourite on the site. Check the last answer ;)

How can I avoid having dependencies injected into an object just so that it can pass them on? Doing so feels wrong and can result in many dependencies being injected into an object.

Most people don't realise that an IOC container makes the need to store temporary dependencies void. This in turn makes your code cleaner and easier to follow. Each class (or module) of your code simply asks for what it needs. IOC Containers can manage object life time, so even if two classes ask for the same dependency independently, they can receive the same instance, which is pretty neat.

Finglas
+2  A: 

I agree with your concerns. It's a code smell to take dependencies for the sole purpose of passing them on to other dependencies.

Depending on the exact interaction between those dependencies, you have a couple of options:

If only one instance of the dependency is needed

If your Controller only needs a single instance of a dependency, then just take a dependency on that instead.

(apologies for the c# code)

Don't do this:

public class MyController
{
    public MyController(IDb db)
    {
        var dep = new MyDependency(db);
        // Use dep or save it for later
    }
}

Instead, you can do this:

public class MyController
{
    public MyController(MyDependency dep)
    {
        // Use dep or save it for later
    }
}

You may want to consider MyDependency behind an interface itself. See also Refactoring to Aggregate Services.

If you need to create multiple instances during the Controller's lifetime

Sometimes, however, you need to create multiple instances dynamically. This is often the case when you need a value that's only available at run-time before you can fully populate a dependency.

In this case, an Abstract Factory is an excellent and universal solution.

Mark Seemann
I don't fully understand what you propose I should do with your first option. Are you bundling the dependencies together and passing them as one?
Pheter
That's one option. The main point, however, is that the consumer shouldn't create the dependency at all, but rather request it by requiring it as a constructor parameter.
Mark Seemann
Isn't bundling the dependencies together and passing them to the controller pretty much the same as passing them all individually? It is a different way of doing it, but you are still passing dependencies to the controller that it doesn't use. I think I might have misunderstood what you meant though!
Pheter
I'm not sure I understand what you mean, then. You should only pass dependencies that you would use. If the Controller doesn't use them, then why would it request them? Surely it must need to interact with *something*?
Mark Seemann
The controller isn't directly using the database object. It is passing the database object to the data access layer. I am looking for a way to get the database object to the DAL without having it go via the controller. It seems, however, that I either have to pass the db object to the controller, or create the db object to the controller. It is not possible to do things the other way round and inject the DAL into the controller.
Pheter
But that's what you should do: Inject the DAL into the Controller. If for technical reasons you can't do this, you should extract an interface from your DAL and inject that into the Controller instead.
Mark Seemann
The controller doesn't have to provide the DAL with the database object, because the controller doesn't "new" up the DAL. The controller asks the IoC container (or an object you create to perform the same function) for the DAL, and the IoC container is responsible for providing the database object to the DAL.
Eric King
@eric I've tried injecting an instance of a factory into the controller. The factory is used to build DAL and provide it with it's dependences; it then returns an instance of the DAL. This seems to work fine and means that the controller is no longer responsible for creating the DAL. When unit testing I can inject a mock factory that will return a different DAL (that provides data for testing purposes). Is this the correct usage of DI?
Pheter
@Pheter: That's certainly one way of doing it. An injected Abstract Factory makes sense when your Controller needs more than one instances of the DAL, or if it needs to collect a run-time value upon which selection of the DAL depends. Otherwise, you might as well just inject the DAL directly. In any case, without code it's pretty hard to say whether what you are trying to do is correct. May I suggest that you edit your question to include some code, or alternatively ask a new question with code?
Mark Seemann
@Pheter - Yes, I'd say that's a good way of doing it.
Eric King