【问题标题】:Dependency Injection and dependencies not used未使用依赖注入和依赖
【发布时间】:2013-07-23 13:58:45
【问题描述】:

首先,对不起我的英语不好,希望你明白我在说什么。

这是我的问题:

假设我有一个 MVC 应用程序,包括标准路由器、控制器、模型(服务)层和某种数据库连接器。
模型层依赖于数据库连接器,控制器依赖于模型/服务,顶层“应用程序”类依赖于路由器和控制器。
我的对象层次结构如下所示:

App -> ControllerFactory -> ServiceFactory -> DAO -> DbConnection

也许,上面写的看起来不是最好的应用程序架构,但我想专注于另一件事:
当我试图实例化一个 App 类时,我应该将所有依赖项传递给实例化的类;类依赖项又具有自己的依赖项,依此类推。
结果,我立即实例化了所有层次结构堆栈。但是如果我在某些情况下不需要访问数据库怎么办?如果某些控制器用于渲染静态模板而无需模型交互怎么办?
我的意思是,如果在某些特殊情况下类不需要自己的依赖项(在某些情况下确实需要)怎么办?我应该有条件地注入依赖项吗?
我真的被困在这一点上,我不知道该怎么办。

【问题讨论】:

    标签: php dependency-injection


    【解决方案1】:

    更新:仔细阅读您的问题后,这里有另一个建议:是的,每个类都有不同的依赖关系。

    不要将每个对象都注入到其他每个对象中。例如,某些服务可能需要 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(这不是问题),但要解决惰性注入,这是一项相当大的工作,您可能需要开始考虑使用它。

    【讨论】:

      【解决方案2】:

      如果你的依赖结构很复杂,只需添加一个新的工厂类,它应该包含为你创建正确对象的所有逻辑。

      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;
          }
      }
      

      【讨论】: