介绍
Inversion of Control,缩写为IoC。
是一种设计原则,可以减小模块之间的耦合,使代码可维护性变高。
IoC提倡:
- 高层模块不应该依赖底层模块。两个都应该依赖抽象
- 抽象不应该依赖细节,细节应该依赖抽象
- 针对接口编程,不要针对实现编程
下面看一个用依赖注入设计模式,实现控制反转的例子:
依赖注入就是在本类中使用其他类的话,不是在本类中实例化,而是通过方法把外部的类注入进来使用,可提高代码重用和可读性。
依赖注入的例子
拿我之前写的compose pack举例:
https://github.com/OX007/easywechatshare
src/Share.php中的Share类需要使用EasyWeChat\Foundation\Application这个实例。
如果在该类中实例化EasyWeChat类则需要配置很多参数,极不易使用。
用依赖注入实现就可以如下代码所示。
这样的话,别人用的时候,就可以把自己的EasyWeChat\Foundation\Application实例传进来就可以,非常方便。
class Share
{
private $wechatApp;
/**
* init wechat option
*
* @param EasyWeChat\Foundation\Application
*/
public function __construct(Application $wechatApp)
{
$this->wechatApp = $wechatApp;
}
...
}
从Laravel底层看控制反转的例子
例如从vendor/laravel/framework/src/Illuminate/Mail/SendQueuedMailable.php
中可以看出,handle方法的 $mailer参数可以是实现了Illuminate\Contracts\Mail\Mailer接口的任何一个实例,这时handle就无须关注要执行的实例具体内容,直接执行即可,反正实例是根据接口类实现的,send方法都会有。
这也正遵循了控制反转的原则,这样的话,多个类的之间的依赖复杂性就降低了,是面向接口编程,都依赖抽象,让实现变得松散耦合
<?php
namespace Illuminate\Mail;
use Illuminate\Contracts\Mail\Mailer as MailerContract;
use Illuminate\Contracts\Mail\Mailable as MailableContract;
class SendQueuedMailable
{
/**
* The mailable message instance.
*
* @var Mailable
*/
protected $mailable;
/**
* Create a new job instance.
*
* @param \Illuminate\Contracts\Mail\Mailable $mailable
* @return void
*/
public function __construct(MailableContract $mailable)
{
$this->mailable = $mailable;
}
/**
* Handle the queued job.
*
* @param \Illuminate\Contracts\Mail\Mailer $mailer
* @return void
*/
public function handle(MailerContract $mailer)
{
$mailer->send($this->mailable);
}
}
再写一个更容易理解的例子
<?php
interface Storage{
public function open();
}
class DatabaseStorage implements Storage {
public function open() {
echo 'open db Storage';
}
}
class FileStorage implements Storage {
public function open() {
echo 'open file Storage';
}
}
class MyController {
private $Storage;
public function initEngine(Storage $Storage)
{
$this->Storage = $Storage;
}
public function open()
{
$this->Storage->open();
}
}
$MyController = new MyController;
$MyController->initEngine(new FileStorage);
$MyController->open(); // open file Storage
?>
参考资料:
https://github.com/seekerliu/laravel-tips/blob/master/what-is-dependency-injection.md
https://medium.com/@amitkma/understanding-inversion-of-control-ioc-principle-163b1dc97454
https://en.wikipedia.org/wiki/Dependency_injection
https://cloud.tencent.com/developer/article/1191956