在理解依赖关系注入时遇到问题
我正在构建一个小项目,试图尽可能多地自学基础知识,这对我来说意味着不使用预制框架(正如Jeff曾经说过的那样,“不要重新发明轮子,除非你打算学习更多关于轮子的知识”[强调我的]),并遵循测试驱动开发的原则。
在我的探索中,我最近遇到了依赖注入的概念,这似乎对TDD至关重要。我的问题是我不能完全把我的头缠绕在它上面。到目前为止,我的理解是,它或多或少相当于“让调用方传递它可能需要的任何其他类/方法,而不是让他们自己创建它们。
我有两个示例问题,我正在尝试使用 DI 解决。我是否在这些重构中走上了正确的轨道?
数据库连接
我计划只使用单例来处理数据库,因为我目前不希望使用多个数据库。最初,我的模型看起来像这样:
class Post {
private $id;
private $body;
public static function getPostById($id) {
$db = Database::getDB();
$db->query("SELECT...");
//etc.
return new Post($id, $body);
}
public function edit($newBody) {
$db = Database::getDB();
$db->query("UPDATE...");
//etc.
}
}
使用DI,我认为它看起来更像这样:
class Post {
private $db; // new member
private $id;
private $body;
public static function getPostById($id, $db) { // new parameter
$db->query("SELECT..."); // uses parameter
//etc.
return new Post($db, $id, $body);
}
public function edit($id, $newBody) {
$this->db->query("UPDATE..."); // uses member
//etc.
}
}
我仍然可以使用单例,并在应用程序设置中指定凭据,但我只需要从控制器传递它(控制器无论如何都是不可单元测试的):
Post::getPostById(123, Database::getDB);
模型调用模型
例如,一个帖子有观看次数。由于确定视图是否为新的逻辑并不特定于 Post 对象,因此它只是其自身对象上的静态方法。然后,Post 对象将调用它:
class Post {
//...
public function addView() {
if (PageView::registerView("post", $this->id) {
$db = Database::getDB();
$db->query("UPDATE..");
$this->viewCount++;
}
}
使用DI,我认为它看起来更像这样:
class Post {
private $db;
//...
public function addView($viewRegistry) {
if ($viewRegistry->registerView("post", $this->id, $this->db) {
$this->db->query("UPDATE..");
$this->viewCount++;
}
}
这会将控制器的调用更改为:
$post->addView(new PageView());
这意味着实例化一个只有静态方法的类的新实例,这对我来说感觉很糟糕(我认为在某些语言中是不可能的,但在这里是可行的,因为PHP不允许类本身是静态的)。
在本例中,我们只深入一个级别,因此让控制器实例化所有内容似乎是可行的(尽管 PageView 类通过 Post 的成员变量间接获取其 DB 连接),但是如果您必须调用一个需要需要类的类的方法,它似乎会变得笨拙。我想这可能只是意味着这也是一种代码气味。
我是否走在正确的轨道上,或者我完全误解了DI?任何批评和建议都非常感谢。