在依赖注入容器中放入什么?DI不是增加了耦合吗?


Excatly what to put into dependency injection conatiner? Isnt DI increases coupling?

虽然我知道它很好用,但不要过度使用。例子:

class Point
{
    private $x, $y, $graphicsEngine;
    public function __constructor($x, $y, $graphicsEngine)
    {
        $this->x = $x;
        $this->y = $y;
        $this->graphicsEngine = $graphicsEngine;
    }
    public function draw()
    {
        $this->graphicsEngine->draw($this);
    }
}
class GraphicsEngine
{
    public function draw(Point $p)
    {
        ....
    }
}
$graphicsEngine = new GraphicsEngine();
$graphicsEngine->draw (new Point(5,2));

Point必须知道GraphicsEngine。如果我把它写成DI形式:

class Point
{
    private $x, $y;
    public function __constructor($x, $y)
    {
        $this->x = $x;
        $this->y = $y;
    }
    public function draw()
    {
        DI::get('graphicsEngine')->draw($this);
    }
}
class GraphicsEngine
{
    public function draw(Point $p)
    {
        ....
    }
}
DI::set('graphicsEngine', new GraphicsEngine());
DI::get('graphicsEngine'->draw (new Point(5,2));
虽然DI本身与应用程序高度耦合,但

代码看起来更轻一些。GraphicsEngine和Point过去是更加独立的,但现在DI与整个应用程序高度耦合。

你的问题是你的对象不应该知道IoC容器的存在:

class Point
{
    private $x, $y;
    public function __constructor($x, $y)
    {
        $this->x = $x;
        $this->y = $y;
    }
    public function draw()
    {
        DI::get('graphicsEngine')->draw($this); // WRONG: DIRECT REFERENCE TO DI!!!
    }
}

我试图帮助,因为我是JavaScript的IoC容器的作者。不幸的是,我不太熟悉您的IoC容器或PHP。我将尽力解释如何解决这个问题。

class Point
{
    private private $x, $y, $graphicsEngine;
    public function __constructor($x, $y)
    {
        $this->x = $x;
        $this->y = $y;
    }
    public function draw()
    {
        // graphicsEngine is only used when draw is invoked
        // we can lazy inject graphicsEngine 
        $this->graphicsEngine->draw($this);
    }
}
class GraphicsEngine
{
    public function draw(Point $p)
    {
        ....
    }
}

要了解如何配置延迟注入,需要参考lazy-injection。

记住,对象不应该知道IoC容器的存在。你的IoC容器将在应用程序的某个地方配置,所有的IoC配置都应该集中在一个文件中。这个文件将充满类型绑定:

 DI::set('X', X);
 DI::set('Y', Y);
 // ...

类型绑定是键(例如graphicsEngine)和实现(例如GraphicsEngine)之间的映射。您可以将IoC容器配置视为类型绑定的字典。

IoC容器拥有类型绑定字典。这意味着IoC容器知道应用程序中的所有类型(类和接口),但是你的类型不知道IoC容器。

IoC容器就像一个"上帝",可以看到所有的东西,而你的对象却不知道这个"上帝"或其他类的存在。您的类不会耦合,但是耦合需要在某个地方进行,这个地方就是IoC配置。

我们可以说IoC容器没有移除耦合,因为耦合在运行时是必需的。IoC容器帮助我们做的是将耦合集中到整个应用程序中的一个点上,而不是到处都有耦合。