1. 模式定义
依赖注入(Dependency Injection)是控制反转(Inversion of Control)的一种实现方式。
控制反转:当调用者需要被调用者的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例,但在这里,创建被调用者的工作不再由调用者来完成,而是将被调用者的创建移到调用者的外部,从而反转被调用者的创建,消除了调用者对被调用者创建的控制,因此称为控制反转。
依赖注入:要实现控制反转,通常的解决方案是将创建被调用者实例的工作交由 IoC 容器来完成,然后在调用者中注入被调用者(通过构造器/方法注入实现),这样我们就实现了调用者与被调用者的解耦,该过程被称为依赖注入。
依赖注入不是目的,它是一系列工具和手段,最终的目的是帮助我们开发出松散耦合(loose coupled)、可维护、可测试的代码和程序。这条原则的做法是大家熟知的面向接口,或者说是面向抽象编程。
2. UML类图
3. 示例代码
本文示例中,Superman 是调用者,UltraBomb和XPower是实现SuperModuleInterface接口的被调用者, Superman 通过构造方法依赖注入了两个SuperModuleInterface接口实现类。如果不使用依赖注入的话,则必须在 Superman 中创建该接口的实现类实例,这就形成紧耦合代码,如果我们要切换成该接口的其它实现类则必须要修改代码,这对到测试和扩展而言都是极为不利的。
SuperModuleInterface.php
<?php
namespace DesignPattern\Structural\DependencyInjection;
interface SuperModuleInterface{
/**
* 超能力激活方法
*
* 任何一个超能力都得有该方法,并拥有一个参数
*@param array $target 针对目标,可以是一个或多个,自己或他人
*/
public function activate(array $target);
}
UltraBomb.php
<?php
namespace DesignPattern\Structural\DependencyInjection;
/**
* 终极炸弹
*/
class UltraBomb implements SuperModuleInterface
{
public function activate(array $targets)
{
$str = '';
foreach ($targets as $target) {
$str .= "对" . $target . "使用 UltraBomb\n";
}
return $str;
}
}
XPower.php
<?php
namespace DesignPattern\Structural\DependencyInjection;
/**
* X-超能量
*/
class XPower implements SuperModuleInterface
{
public function activate(array $targets)
{
$str = '';
foreach ($targets as $target) {
$str .= "对" . $target . "使用 XPower\n";
}
return $str;
}
}
Superman.php
<?php
namespace DesignPattern\Structural\DependencyInjection;
class Superman
{
protected $module;
public function __construct(SuperModuleInterface $module)
{
$this->module = $module;
}
public function fire(array $targets){
return $this->module->activate($targets);
}
}
单元测试 DependencyInjectionTest.php
<?php
namespace DesignPattern\Tests;
use DesignPattern\Structural\DependencyInjection\Superman;
use DesignPattern\Structural\DependencyInjection\UltraBomb;
use DesignPattern\Structural\DependencyInjection\XPower;
use PHPUnit\Framework\TestCase;
/**
* 依赖注入模式
* Class SingletonTest
* @package Creational\Singleton\Tests
*/
class DependencyInjectionTest extends TestCase
{
protected $config;
protected $source;
public function testDependencyInjection()
{
// 超能力模组
$superModule = new XPower();
// 初始化一个超人,并注入一个超能力模组依赖
$superMan = new Superman($superModule);
$result1 = $superMan->fire(['user1', 'user2']);
$this->assertEquals("对user1使用 XPower\n对user2使用 XPower\n", $result1);
// 超能力模组
$superModule2 = new UltraBomb();
// 初始化一个超人,并注入一个超能力模组依赖
$superMan2 = new Superman($superModule2);
$result2 = $superMan2->fire(['user3']);
$this->assertEquals("对user3使用 UltraBomb\n", $result2);
}
}
参考文档:https://laravelacademy.org/post/2792
https://laravelacademy.org/post/769.html
教程源码:https://github.com/SylviaYuan1995/DesignPatternDemo