依赖注入的目的是实现松耦合,以便更好的测试、管理和扩展代码。
控制反转(Inversion of Control):当调用者需要被调用者的协助时,传统方法通常由调用者来创建被调用者的实例,但在这里,创建被调用者的工作不再由调用者来完成,而是移到调用者的外部,从而反转被调用者的创建,消除了调用者对被调用者创建的控制,因此称为控制反转。
依赖注入(Dependency Injection):要实现控制反转,通常是将创建被调用者实例的工作交由IoC容器来完成,然后在调用者中注入被调用者(通过构造器或方法注入),这样就实现了调用者与被调用者的解耦,该过程称为依赖注入。依赖注入是控制反转的一种实现方式。
容器(Container):管理对象的生成、资源取得、销毁等生命周期,建立对象与对象之间的依赖关系,可以延时加载对象。
实例:
// 定义日志接口
interface Log {
public function write();
}
// 文件记录日志
class FileLog implements Log
{
public function write()
{
echo 'file log';
}
}
// 数据库记录日志
class DatabaseLog implements Log
{
public function write()
{
echo 'db log';
}
}
// 定义一个测试类
class Test
{
protected $fileLog;
public function __construct()
{
$this->fileLog = new FileLog();
}
public function do()
{
// 其他代码
// 文件日志记录
$this->fileLog->write();
}
}
(new Test())->do();
上面做法实现了文件记录日志的功能,但是假设现在想用数据库记录日志的话,就得修改Test类,这样没达到解耦目的,因此我们可以把日志处理类通过构造函数方式传递进去。
class Test
{
protected $log;
public function __construct(Log $log)
{
$this->log = $log;
}
public function do()
{
// 其他代码逻辑 .......
// 写日志
$this->log->write();
}
}
// 调用
(new Test(new DatabaseLog()))->do();
以后不管你想用哪个方式记录日志都不需要去改Test类了,只需要通过构造函数参数传递就可以实现,这就是“控制反转”。不需要自己内容修改,改成由外部传递(由外部负责其依赖需求)。
上面的例子也算是依赖注入,不是由自己内部new对象或者实例,通过构造函数,或者方法传入的都属于依赖注入(DI) 。
网友评论