依赖注入模式

目的

为了实现松散耦合的架构,以获得更好的可测试、可维护和可扩展的代码。

用法

下面的代码定义了 DatabaseConfiguration 类,该类的实例将被注入到 DatabaseConnection 对象中。DatabaseConnection 会从注入的 DatabaseConfiguration 中获取所有需要的变量。如果不使用依赖注入的方式,数据库配置对象将直接在 DatabaseConnection 中创建,这不利于测试和扩展。

使用场景

  • Doctrine2 中的 ORM 使用了依赖注入。例如,它使用的配置是注入到 Connection 对象中的。为了方便测试,我们可以很轻松地创建一个模拟配置对象,并将其注入到 Connection 对象中
  • 许多框架已经实现了依赖注入容器,通过配置数组来创建对象,并在需要的地方注入它们(例如,在控制器中)

UML 类图

依赖注入模式类图

代码

DatabaseConfiguration.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php declare(strict_types = 1);

namespace DesignPatterns\Extend\DependencyInjection;

class DatabaseConfiguration
{
private string $host;
private int $port;
private string $username;
private string $password;

public function __construct(string $host, int $port, string $username, string $password)
{
$this->host = $host;
$this->port = $port;
$this->username = $username;
$this->password = $password;
}

public function getHost(): string
{
return $this->host;
}

public function getPort(): int
{
return $this->port;
}

public function getUsername(): string
{
return $this->username;
}

public function getPassword(): string
{
return $this->password;
}
}

DatabaseConnection.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php declare(strict_types = 1);

namespace DesignPatterns\Extend\DependencyInjection;

class DatabaseConnection
{
private DatabaseConfiguration $configuration;

public function __construct(DatabaseConfiguration $config)
{
$this->configuration = $config;
}

public function getDsn(): string
{
// this is just for the sake of demonstration, not a real DSN
// notice that only the injected config is used here, so there is
// a real separation of concerns here
return sprintf(
'%s:%s@%s:%d',
$this->configuration->getUsername(),
$this->configuration->getPassword(),
$this->configuration->getHost(),
$this->configuration->getPort()
);
}
}

测试

Tests/DependencyInjectionTest.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php declare(strict_types = 1);

namespace DesignPatterns\Extend\DependencyInjection\Tests;

use DesignPatterns\Extend\DependencyInjection\DatabaseConfiguration;
use DesignPatterns\Extend\DependencyInjection\DatabaseConnection;
use PHPUnit\Framework\TestCase;

class DependencyInjectionTest extends TestCase
{
public function testDependencyInjection()
{
$config = new DatabaseConfiguration('localhost', 3306, 'domnikl', '1234');
$connection = new DatabaseConnection($config);

$this->assertSame('domnikl:1234@localhost:3306', $connection->getDsn());
}
}