虽然我知道它很好用,但不要过度使用。例子:
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容器帮助我们做的是将耦合集中到整个应用程序中的一个点上,而不是到处都有耦合。