依赖注入混淆

时间:2013-01-18 20:48:46

标签: php oop

我一直在阅读有关依赖注入的内容,但我发现的示例对我来说看起来很糟糕,所以我的主要问题是我是正确的认为它是错误的代码,还是我误解了它的目的,并且我的榜样更好吗?

class Photo {
   protected $db;
   public function __construct()
   {
      $this->db = DB::getInstance();
   }
}

所以这是错误的代码,并且由于在我们明确设置每个变量时可能创建的大量setter,因此依赖注入的建议是:

class Container {
   protected $db;
   public static newPhoto()
   {
      $photo = new Photo;
      $photo->setDB(static::$db);
      $photo->setConfig();
      $photo->setResponse();
      return $photo;
   }
}
$photo = Container::newPhoto();

但是如果我错了,请纠正我,我们刚刚建立了一个类,它唯一的责任是构建另一个类,看起来毫无意义,而且我们使用静态方法,这显然是一个非常糟糕的主意。

我确实看到的一个好处,令我惊讶的是我没有提到我们现在可以通过使用setter独立测试Photo类,而在第一个例子中我们不能。

这样的事情对我来说更有意义:

class Photo {
   protected $db;
   protected $config;
   protected $response;
   public function __construct($dbConn=null,$config='123',$response=true)
   {
      if(is_null($dbConn))
          $this->db = DB::getInstance();
      else
          $this->db = $dbConn;
      ...etc
   }
}
$photo = new Photo($dbConn);

该类构建自身,不需要实际调用静态方法,如果使用值,则可以使用虚拟数据测试类,否则它将返回默认值(这似乎是Container的唯一点) class),与Container相比,依赖关系仍然有些明显。

2 个答案:

答案 0 :(得分:2)

依赖注入模式的目标是分离如何构造一起工作的对象。在您的示例中,Photo类不关心如何构建数据库实例,而只是使用数据库实例来实现其目标。

您已经注意到的明显优势是在测试中,如果您只想测试Photo功能,可以轻松传递模拟数据库实例。但您也可以考虑连接池,例如,容器具有数据库实例池并将其中一个传递给您的Photo对象以执行其工作。当Photo生命周期结束时,数据库实例将返回到池中并在其他地方使用。

可以使用带有参数,setter,注释(至少在Java中)甚至XML配置文件的构造函数来实现此模式的实现。对于注释或XML配置文件,容器将解析该信息,创建适当的所需对象并将其注入客户端类。

您在C1和C2中描述的是一个工厂类,它公开了用于获取Photo实例的静态方法。这是Java中许多地方使用的非常常见的模式。

答案 1 :(得分:1)

  

我不知道你在哪里倾向于DI,但资源似乎很值得怀疑。相反,您应该首先观看this lecture,然后是来自 Martin Fowler article。可能由this短视频补充。

class Container {
   protected $db;
   public static newPhoto()
   {
      $photo = new Photo;
      $photo->setDB(static::$db);
      $photo->setConfig();
      $photo->setResponse();
      return $photo;
   }
}
$photo = Container::newPhoto();

这不是实现依赖注入。它实际上只是一个实现不好的静态工厂方法(反)模式的例子。特别是神奇的方法$photo->setConfig()$photo->setResponse()显然做了一些工作,但没有收到任何参数。

然后是这段代码:

class Photo {
   protected $db;
   protected $config;
   protected $response;
   public function __construct($dbConn=null,$config='123',$response=true)
   {
      if(is_null($dbConn))
          $this->db = DB::getInstance();
      else
          $this->db = $dbConn;
      ...etc
   }
}
$photo = new Photo($dbConn);

您决定隐藏它的依赖关系,而不是仅仅分配值,如果没有提供它们,则从全局范围中获取它们。当然,您的构造函数最终会包含相当多的计算日志。从而使其无法实现。

哦..然后有神奇的布尔值。无论何时将这样的参数分配给构造函数中的类,都清楚地表明您实际上需要两个不同的类,它们实现相同的接口。

所以..回答你的问题:

  

我一直在阅读有关依赖注入的内容,但我发现的示例对我来说看起来很糟糕,所以我的主要问题是我是正确的认为它是错误的代码,还是我误解了它的目的,并且我的榜样更好吗?

没有。你的榜样并不好。您只需将早期代码示例中最差的部分组合在单个类定义中。