依赖注入模式(Dependency Injection)

目的

用松散耦合的方式来更好的实现可测试、可维护和可扩展的代码。

依赖注入模式:依赖注入(Dependency Injection)是控制反转(Inversion of Control)的一种实现方式。要实现控制反转,通常的解决方案是将创建被调用者实例的工作交由 IoC 容器来完成,然后在调用者中注入被调用者(通过构造器/方法注入实现),这样我们就实现了调用者与被调用者的解耦,该过程被称为依赖注入。

用法

DatabaseConfiguration 被注入 DatabaseConnection 并获取所需的 $config 。如果没有依赖注入模式, 配置将直接创建 DatabaseConnection 。这对测试和扩展来说很不好。

例子

  • Doctrine2 ORM 使用依赖注入。 例如,注入到 Connection 对象的配置。 对于测试而言, 可以轻松的创建可扩展的模拟数据并注入到 Connection 对象中。
  • Symfony 和 Zend Framework 2 已经有了依赖注入的容器。他们通过配置的数组来创建对象,并在需要的地方注入 (在控制器中)。

UML 图

MihvMhMofO.png

代码

您可以在 GitHub 查看这段代码

DatabaseConfiguration.php

  1. <?php
  2. namespace DesignPatterns\Structural\DependencyInjection;
  3. class DatabaseConfiguration
  4. {
  5. /**
  6. * @var string
  7. */
  8. private $host;
  9. /**
  10. * @var int
  11. */
  12. private $port;
  13. /**
  14. * @var string
  15. */
  16. private $username;
  17. /**
  18. * @var string
  19. */
  20. private $password;
  21. public function __construct(string $host, int $port, string $username, string $password)
  22. {
  23. $this->host = $host;
  24. $this->port = $port;
  25. $this->username = $username;
  26. $this->password = $password;
  27. }
  28. public function getHost(): string
  29. {
  30. return $this->host;
  31. }
  32. public function getPort(): int
  33. {
  34. return $this->port;
  35. }
  36. public function getUsername(): string
  37. {
  38. return $this->username;
  39. }
  40. public function getPassword(): string
  41. {
  42. return $this->password;
  43. }
  44. }

DatabaseConnection.php

  1. <?php
  2. namespace DesignPatterns\Structural\DependencyInjection;
  3. class DatabaseConnection
  4. {
  5. /**
  6. * @var DatabaseConfiguration
  7. */
  8. private $configuration;
  9. /**
  10. * @param DatabaseConfiguration $config
  11. */
  12. public function __construct(DatabaseConfiguration $config)
  13. {
  14. $this->configuration = $config;
  15. }
  16. public function getDsn(): string
  17. {
  18. // 这仅仅是演示,而不是一个真正的 DSN
  19. // 注意,这里只使用了注入的配置。 所以,
  20. // 这里是关键的分离关注点。
  21. return sprintf(
  22. '%s:%s@%s:%d',
  23. $this->configuration->getUsername(),
  24. $this->configuration->getPassword(),
  25. $this->configuration->getHost(),
  26. $this->configuration->getPort()
  27. );
  28. }
  29. }

测试

Tests/DependencyInjectionTest.php

  1. <?php
  2. namespace DesignPatterns\Structural\DependencyInjection\Tests;
  3. use DesignPatterns\Structural\DependencyInjection\DatabaseConfiguration;
  4. use DesignPatterns\Structural\DependencyInjection\DatabaseConnection;
  5. use PHPUnit\Framework\TestCase;
  6. class DependencyInjectionTest extends TestCase
  7. {
  8. public function testDependencyInjection()
  9. {
  10. $config = new DatabaseConfiguration('localhost', 3306, 'domnikl', '1234');
  11. $connection = new DatabaseConnection($config);
  12. $this->assertEquals('domnikl:1234@localhost:3306', $connection->getDsn());
  13. }
  14. }