3

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

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

所以这是一个糟糕的代码,依赖注入的建议是:

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

但是,如果我错了,请纠正我,我们刚刚构建了一个类,其唯一职责是构建另一个类,这似乎毫无意义,而且我们正在使用静态方法,这显然是一个非常糟糕的主意。

我确实看到的一个好处是,令我惊讶的是没有提到我们现在可以使用设置器独立测试 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 类的唯一点),与容器相比,依赖关系仍然有些明显。

4

2 回答 2

2

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

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

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

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

于 2013-01-18T21:27:47.567 回答
1

我不知道你对 DI 的看法,但资源似乎很可疑。相反,您应该从观看本讲座开始,然后是Martin Fowler的文章也许通过这个短片补充。

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

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

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

所以..回答你的问题:

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

不,你的例子并不好。您刚刚将两个早期代码示例中最糟糕的部分组合到单个类定义中。

于 2013-01-18T22:51:13.470 回答