Age*_*rum 18 php oop model-view-controller tdd dependency-injection
我正在建立一个小项目,试图尽可能多地教自己,这对我来说意味着不使用预制框架(正如杰夫曾经说过的那样,"不要重新发明轮子,除非你打算学习更多关于轮子 "[强调我的]"并遵循测试驱动开发的原则.
在我的追求中,我最近遇到了依赖注入的概念,这对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.
}
}
Run Code Online (Sandbox Code Playgroud)
使用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.
}
}
Run Code Online (Sandbox Code Playgroud)
我仍然可以使用单例,在应用程序设置中指定凭据,但我只需要从控制器传递它(控制器无论如何都是单元可测试的):
Post::getPostById(123, Database::getDB);
Run Code Online (Sandbox Code Playgroud)
以一个有视图计数的帖子为例.由于确定视图是否为新的逻辑并不是Post对象特有的,因此它本身就是一个静态方法.然后Post对象将调用它:
class Post {
//...
public function addView() {
if (PageView::registerView("post", $this->id) {
$db = Database::getDB();
$db->query("UPDATE..");
$this->viewCount++;
}
}
Run Code Online (Sandbox Code Playgroud)
使用DI,我觉得它看起来更像是这样的:
class Post {
private $db;
//...
public function addView($viewRegistry) {
if ($viewRegistry->registerView("post", $this->id, $this->db) {
$this->db->query("UPDATE..");
$this->viewCount++;
}
}
Run Code Online (Sandbox Code Playgroud)
这会将来自控制器的调用更改为:
$post->addView(new PageView());
Run Code Online (Sandbox Code Playgroud)
这意味着实例化一个只有静态方法的类的新实例,这对我来说很难闻(我认为在某些语言中是不可能的,但在这里可行,因为PHP不允许类本身是静态的).
在这种情况下,我们只是深入一级,所以让控制器实例化一切看起来都是可行的(虽然PageView类通过Post的成员变量间接获得它的DB连接),但是看起来它可能会变得笨拙如果你不得不调用一个需要一个类需要一个类的类的方法.我想这可能只是意味着代码闻起来了.
我是在正确的轨道上,还是我完全误解了DI?任何批评和建议都非常感谢.
是.看起来你有正确的想法.您将看到,当您实现DI时,所有依赖项将浮动到"顶部".将所有内容放在顶部可以轻松模拟必要的测试对象.
拥有一个需要一个类需要一个类的类并不是一件坏事.你在那里描述的是你的对象图.这对于DI来说是正常的.让我们以House对象为例.它依赖于厨房; 厨房依赖于水槽; 水槽依赖于水龙头等.众议院的实例化看起来像new House(new Kitchen(new Sink(new Faucet()))).这有助于实施单一责任原则.(另外,你应该在工厂或建筑商这样的实例化工作中进一步执行单一责任原则.)
Misko Hevery撰写了大量有关DI的文章.他的博客是一个很好的资源.他还指出了一些常见的缺陷(构造函数真正的工作,挖掘合作者,脆弱的全局状态和单身,并且课程做得太多),并带有警告标志来发现它们以及修复它们的方法.有时值得一试.
| 归档时间: |
|
| 查看次数: |
1448 次 |
| 最近记录: |