Reputation: 1952
First of all, sorry for my bad English, I hope you understand what I'm saying.
Here is my problem:
Lets assume i have an MVC application including standard router, controller, model(service) layer and some kind of db connector.
Model layer depends on a db connector, controllers depends on models/services and the top-level "application" class depends on routers and controllers.
My object hierarchy looks like this:
App -> ControllerFactory -> ServiceFactory -> DAO -> DbConnection
Perhaps, written above doesn't look like best application architecture ever, but i want to focus on the other thing:
When i'm trying to instantiate an App class i should pass all dependencies to the class instantiated; class dependencies, in turn, has their own dependencies and so on.
As a result I get all hierarchy stack instantiated at once. But what if i dont need to access the database in some cases; what if some controllers are used for rendering static templates without model interaction?
I mean, what if there are some special cases when class does not require its own dependencies(and in some cases it does)? Should i inject dependencies conditionaly or something?
I'm really stuck at this point and i don't know what to do.
Upvotes: 3
Views: 240
Reputation: 1196
If your dependency construction is complex, simply add a new factory class that should contain all the logic to create a correct object for you.
class AppFactory(){
__construct(all params){
}
build(useDB=true){
// logic to build
if(useDB){
App = new App(new ControllerFactory(new ServiceFactory(new DAO(new DbConnection(params)))))
} else {
App = new App(new ControllerFactory(new ServiceFactory(null))))
}
return App;
}
}
Upvotes: 0
Reputation: 49703
Update: after re-reading carefully your question, here is another advice: yes, every class has different dependencies.
Don't inject every object into every other object. For example, some services might need DAOs, so inject them. But if a service doesn't need a DAO, don't inject any DAO.
The rest of my answer is valid if you have (for example) a service that needs a DAO (and thus a DB connection) not for every method.
What you may be looking for is lazy injection.
It is the act of injecting a dependency not loaded, so that the object is loaded only if/when used.
In conrete terms, that means injecting a proxy object, that would look like and behave exactly like the original object (for example, the db connection).
Several DI container (frameworks) support this so you don't have to create proxies yourself. I'll take as an example PHP-DI (I work on that project FYI).
Here is an example using annotations:
use DI\Annotation\Inject;
class Example {
/**
* @Inject(lazy=true)
* @var My\Class
*/
protected $property;
/**
* @Inject({ "param1" = {"lazy"=true} })
*/
public function method(My\Class $param1) {
}
}
Of course if you don't want to use annotations you can use any other configuration you want (PHP, YAML, …). Here is the same example by configuring the container in pure PHP:
$container->set('Example')
->withProperty('property', 'My\Class', true)
->withMethod('method', array('param1' => array(
'name' => 'My\Class',
'lazy' => true,
)));
See more in the documentation about Lazy Injection.
Note: you may not be using a Container for now (and that's not a problem), but for tackling lazy injection this is a fair amount of work and you might need to start considering using one.
Upvotes: 3