我一直在阅读有关依赖注入的内容,但我发现的示例对我来说看起来很糟糕,所以我的主要问题是我是正确的认为它是错误的代码,还是我误解了它的目的,并且我的榜样更好吗?
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相比,依赖关系仍然有些明显。
答案 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);
您决定隐藏它的依赖关系,而不是仅仅分配值,如果没有提供它们,则从全局范围中获取它们。当然,您的构造函数最终会包含相当多的计算日志。从而使其无法实现。
哦..然后有神奇的布尔值。无论何时将这样的参数分配给构造函数中的类,都清楚地表明您实际上需要两个不同的类,它们实现相同的接口。
所以..回答你的问题:
我一直在阅读有关依赖注入的内容,但我发现的示例对我来说看起来很糟糕,所以我的主要问题是我是正确的认为它是错误的代码,还是我误解了它的目的,并且我的榜样更好吗?
没有。你的榜样并不好。您只需将早期代码示例中最差的部分组合在单个类定义中。