中介者模式(Mediator)

目的

本模式提供了一种轻松的多组件之间弱耦合的协同方式。如果你有个“情报中心”,观察者模式也是个好选择,类似于控制器(并非 MVC 意义上的控制器)。

所有关联协同的组件(称作 Colleague)仅与 MediatorInterface 接口建立耦合,面向对象编程中这是好事,一个良友胜于有多个朋友。这是该模式的重要特性。

UML 图

file

代码

代码查看 GitHub

MediatorInterface.php

  1. <?php
  2. namespace DesignPatterns\Behavioral\Mediator;
  3. /**
  4. * MediatorInterface 接口为 Mediator 类建立契约
  5. * 该接口虽非强制,但优于 Liskov 替换原则。
  6. */
  7. interface MediatorInterface
  8. {
  9. /**
  10. * 发出响应
  11. *
  12. * @param string $content
  13. */
  14. public function sendResponse($content);
  15. /**
  16. * 做出请求
  17. */
  18. public function makeRequest();
  19. /**
  20. * 查询数据库
  21. */
  22. public function queryDb();
  23. }

Mediator.php

  1. <?php
  2. namespace DesignPatterns\Behavioral\Mediator;
  3. /**
  4. * Mediator 是用于访设计模式的中介者模式的实体
  5. *
  6. * 本示例中,我用中介者模式做了一个 “Hello World” 的响应
  7. */
  8. class Mediator implements MediatorInterface
  9. {
  10. /**
  11. * @var Subsystem\Server
  12. */
  13. private $server;
  14. /**
  15. * @var Subsystem\Database
  16. */
  17. private $database;
  18. /**
  19. * @var Subsystem\Client
  20. */
  21. private $client;
  22. /**
  23. * @param Subsystem\Database $database
  24. * @param Subsystem\Client $client
  25. * @param Subsystem\Server $server
  26. */
  27. public function __construct(Subsystem\Database $database, Subsystem\Client $client, Subsystem\Server $server)
  28. {
  29. $this->database = $database;
  30. $this->server = $server;
  31. $this->client = $client;
  32. $this->database->setMediator($this);
  33. $this->server->setMediator($this);
  34. $this->client->setMediator($this);
  35. }
  36. public function makeRequest()
  37. {
  38. $this->server->process();
  39. }
  40. public function queryDb(): string
  41. {
  42. return $this->database->getData();
  43. }
  44. /**
  45. * @param string $content
  46. */
  47. public function sendResponse($content)
  48. {
  49. $this->client->output($content);
  50. }
  51. }

Colleague.php

  1. <?php
  2. namespace DesignPatterns\Behavioral\Mediator;
  3. /**
  4. * Colleague 是个抽象类,该类对象虽彼此协同却不知彼此,只知中介者 Mediator 类
  5. */
  6. abstract class Colleague
  7. {
  8. /**
  9. * 确保子类不变化。
  10. *
  11. * @var MediatorInterface
  12. */
  13. protected $mediator;
  14. /**
  15. * @param MediatorInterface $mediator
  16. */
  17. public function setMediator(MediatorInterface $mediator)
  18. {
  19. $this->mediator = $mediator;
  20. }
  21. }

Subsystem/Client.php

  1. <?php
  2. namespace DesignPatterns\Behavioral\Mediator\Subsystem;
  3. use DesignPatterns\Behavioral\Mediator\Colleague;
  4. /**
  5. * Client 类是一个发出请求并获得响应的客户端。
  6. */
  7. class Client extends Colleague
  8. {
  9. public function request()
  10. {
  11. $this->mediator->makeRequest();
  12. }
  13. public function output(string $content)
  14. {
  15. echo $content;
  16. }
  17. }

Subsystem/Database.php

  1. <?php
  2. namespace DesignPatterns\Behavioral\Mediator\Subsystem;
  3. use DesignPatterns\Behavioral\Mediator\Colleague;
  4. class Database extends Colleague
  5. {
  6. public function getData(): string
  7. {
  8. return 'World';
  9. }
  10. }

Subsystem/Server.php

  1. <?php
  2. namespace DesignPatterns\Behavioral\Mediator\Subsystem;
  3. use DesignPatterns\Behavioral\Mediator\Colleague;
  4. class Server extends Colleague
  5. {
  6. public function process()
  7. {
  8. $data = $this->mediator->queryDb();
  9. $this->mediator->sendResponse(sprintf("Hello %s", $data));
  10. }
  11. }

测试

Tests/MediatorTest.php

  1. <?php
  2. namespace DesignPatterns\Tests\Mediator\Tests;
  3. use DesignPatterns\Behavioral\Mediator\Mediator;
  4. use DesignPatterns\Behavioral\Mediator\Subsystem\Client;
  5. use DesignPatterns\Behavioral\Mediator\Subsystem\Database;
  6. use DesignPatterns\Behavioral\Mediator\Subsystem\Server;
  7. use PHPUnit\Framework\TestCase;
  8. class MediatorTest extends TestCase
  9. {
  10. public function testOutputHelloWorld()
  11. {
  12. $client = new Client();
  13. $client->setMediator(new Mediator(new Database(), $client, new Server()));
  14. $this->expectOutputString('Hello World');
  15. $client->request();
  16. }
  17. }