流接口模式(Fluent Interface)

目的

用来编写易于阅读的代码,就像自然语言一样(如英语)

例子

  • Doctrine2 的 QueryBuilder,就像下面例子中类似
  • PHPUnit 使用连贯接口来创建 mock 对象
  • Yii 框架:CDbCommand 与 CActiveRecord 也使用此模式

UML 图

K6NHRBLVHw.png

代码

你可以在 GitHub 上找到这些代码

Sql.php

  1. <?php
  2. namespace DesignPatterns\Structural\FluentInterface;
  3. class Sql
  4. {
  5. /**
  6. * @var array
  7. */
  8. private $fields = [];
  9. /**
  10. * @var array
  11. */
  12. private $from = [];
  13. /**
  14. * @var array
  15. */
  16. private $where = [];
  17. public function select(array $fields): Sql
  18. {
  19. $this->fields = $fields;
  20. return $this;
  21. }
  22. public function from(string $table, string $alias): Sql
  23. {
  24. $this->from[] = $table.' AS '.$alias;
  25. return $this;
  26. }
  27. public function where(string $condition): Sql
  28. {
  29. $this->where[] = $condition;
  30. return $this;
  31. }
  32. public function __toString(): string
  33. {
  34. return sprintf(
  35. 'SELECT %s FROM %s WHERE %s',
  36. join(', ', $this->fields),
  37. join(', ', $this->from),
  38. join(' AND ', $this->where)
  39. );
  40. }
  41. }

测试

Tests/FluentInterfaceTest.php

  1. <?php
  2. namespace DesignPatterns\Structural\FluentInterface\Tests;
  3. use DesignPatterns\Structural\FluentInterface\Sql;
  4. use PHPUnit\Framework\TestCase;
  5. class FluentInterfaceTest extends TestCase
  6. {
  7. public function testBuildSQL()
  8. {
  9. $query = (new Sql())
  10. ->select(['foo', 'bar'])
  11. ->from('foobar', 'f')
  12. ->where('f.bar = ?');
  13. $this->assertEquals('SELECT foo, bar FROM foobar AS f WHERE f.bar = ?', (string) $query);
  14. }
  15. }