首先,对不起我的英语不好,我希望你明白我在说什么。
这是我的问题:
让我们假设我有一个MVC应用程序,包括标准路由器,控制器,模型(服务)层和某种数据库连接器。
模型层依赖于db连接器,控制器依赖于模型/服务,顶级“应用程序”类依赖于路由器和控制器。
我的对象层次结构如下所示:
App -> ControllerFactory -> ServiceFactory -> DAO -> DbConnection
也许,上面写的看起来并不像最好的应用程序架构,但我想专注于另一件事:
当我试图实例化一个App类时,我应该将所有依赖项传递给实例化的类;反过来,类依赖关系也有自己的依赖关系等等
结果,我立即实例化了所有层次结构堆栈。但是如果在某些情况下我不需要访问数据库呢?如果某些控制器用于渲染静态模板而没有模型交互怎么办?
我的意思是,如果有一些特殊情况,当类不需要自己的依赖项时(在某些情况下它确实如此)会怎么样?我应该注入依赖性条件还是什么?
我真的被困在这一点上,我不知道该怎么做。
答案 0 :(得分:3)
更新:仔细阅读你的问题之后,这是另一个建议:是的,每个类都有不同的依赖。
不要将每个对象都注入到每个其他对象中。例如,某些服务可能需要DAO,因此请注入它们。但是如果服务不需要DAO,请不要注入任何DAO。
如果您(例如)某个服务需要DAO(因此是数据库连接)而不是每个方法,那么我的答案的其余部分都是有效的。
您可能正在寻找的是懒惰注射。
这是注入依赖未加载的行为,因此只有在/使用时才加载对象。
相反,这意味着注入一个代理对象,它看起来和行为完全类似于原始对象(例如,数据库连接)。
几个DI容器(框架)支持这一点,因此您不必自己创建代理。我将以PHP-DI为例(我在该项目上工作)。
以下是使用注释的示例:
use DI\Annotation\Inject;
class Example {
/**
* @Inject(lazy=true)
* @var My\Class
*/
protected $property;
/**
* @Inject({ "param1" = {"lazy"=true} })
*/
public function method(My\Class $param1) {
}
}
当然,如果您不想使用注释,可以使用您想要的任何其他配置(PHP,YAML,...)。这是通过在纯PHP中配置容器的相同示例:
$container->set('Example')
->withProperty('property', 'My\Class', true)
->withMethod('method', array('param1' => array(
'name' => 'My\Class',
'lazy' => true,
)));
在the documentation about Lazy Injection中查看更多内容。
注意:你现在可能没有使用Container(这不是问题),但是对于懒惰注入来说这是一项相当多的工作,你可能需要开始考虑使用它。
答案 1 :(得分:0)
如果您的依赖关系构造很复杂,只需添加一个新工厂类,该工厂类应包含为您创建正确对象的所有逻辑。
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;
}
}