多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] ## 概述 **使用示例:** 生成器模式是 PHP 世界中的一个著名模式。当你需要创建一个可能有许多配置选项的对象时,该模式会特别有用。 **识别方法:** 生成器模式可以通过类来识别, 它拥有一个构建方法和多个配置结果对象的方法。 生成器方法通常支持方法链 (例如 `someBuilder->setValueA(1)->setValueB(2)->create()` ) ## 概念示例 <details> <summary>main.php</summary> ``` <?php // 生成器 (Builder) 接口声明在所有类型生成器中通用的产品构造步骤 interface Builder { public function producePartA(): void; public function producePartB(): void; public function producePartC(): void; } // 具体生成器 (Concrete Builders) 提供构造过程的不同实现。 具体生成器也可以构造不遵循通用接口的产品。 class ConcreteBuilder1 implements Builder { private $product; public function __construct() { $this->reset(); } public function reset(): void { $this->product = new Product1(); } public function producePartA(): void { $this->product->parts[] = "PartA1"; } public function producePartB(): void { $this->product->parts[] = "PartB1"; } public function producePartC(): void { $this->product->parts[] = "PartC1"; } public function getProduct(): Product1 { $result = $this->product; $this->reset(); return $result; } } // 产品 (Products) 是最终生成的对象。 由不同生成器构造的产品无需属于同一类层次结构或接口。 class Product1 { public $parts = []; public function listParts(): void { echo "Product parts: " . implode(', ', $this->parts) . "\n\n"; } } // 主管 (Director) 类定义调用构造步骤的顺序, 这样你就可以创建和复用特定的产品配置。 class Director { /** * @var Builder */ private $builder; public function setBuilder(Builder $builder): void { $this->builder = $builder; } public function buildMinimalViableProduct(): void { $this->builder->producePartA(); } public function buildFullFeaturedProduct(): void { $this->builder->producePartA(); $this->builder->producePartB(); $this->builder->producePartC(); } } // 客户端 (Client) 必须将某个生成器对象与主管类关联。 function clientCode(Director $director) { $builder = new ConcreteBuilder1(); $director->setBuilder($builder); echo "构造标准基础产品:\n"; $director->buildMinimalViableProduct(); $builder->getProduct()->listParts(); echo "构造标准全功能产品:\n"; $director->buildFullFeaturedProduct(); $builder->getProduct()->listParts(); // 记住,Builder模式可以在没有主任类的情况下使用。 echo "自定义产品:\n"; $builder->producePartA(); $builder->producePartC(); $builder->getProduct()->listParts(); } $director = new Director(); clientCode($director); ``` </details> <br /> 输出 ``` 构造标准基础产品: Product parts: PartA1 构造标准全功能产品: Product parts: PartA1, PartB1, PartC1 自定义产品: Product parts: PartA1, PartC1 ``` ## 真实世界示例 生成器模式最好的应用方式之一是 SQL 查询生成器,生成器接口定义了生成一般 SQL 查询所需的通用步骤。 另一方面, 对应不同 SQL 语言的具体生成器会去实现这些步骤, 返回能在特定数据库引擎中执行的 SQL 查询语句 <details> <summary>main.php</summary> ``` <?php interface SQLQueryBuilder { public function select(string $table, array $fields): SQLQueryBuilder; public function where(string $field, string $value, string $operator = '='): SQLQueryBuilder; public function limit(int $start, int $offset): SQLQueryBuilder; //100种其他SQL语法方法。。。 public function getSQL(): string; } class MysqlQueryBuilder implements SQLQueryBuilder { protected $query; protected function reset(): void { $this->query = new stdClass(); } /** * Build a base SELECT query. */ public function select(string $table, array $fields): SQLQueryBuilder { $this->reset(); $this->query->base = "SELECT " . implode(", ", $fields) . " FROM " . $table; $this->query->type = 'select'; return $this; } public function where(string $field, string $value, string $operator = '='): SQLQueryBuilder { if (!in_array($this->query->type, ['select', 'update', 'delete'])) { throw new Exception("WHERE can only be added to SELECT, UPDATE OR DELETE"); } $this->query->where[] = "$field $operator '$value'"; return $this; } public function limit(int $start, int $offset): SQLQueryBuilder { if (!in_array($this->query->type, ['select'])) { throw new \Exception("LIMIT can only be added to SELECT"); } $this->query->limit = " LIMIT " . $start . ", " . $offset; return $this; } public function getSQL(): string { $query = $this->query; $sql = $query->base; if (!empty($query->where)) { $sql .= " WHERE " . implode(' AND ', $query->where); } if (isset($query->limit)) { $sql .= $query->limit; } $sql .= ";"; return $sql; } } class PostgresQueryBuilder extends MysqlQueryBuilder { public function limit(int $start, int $offset): SQLQueryBuilder { parent::limit($start, $offset); $this->query->limit = " LIMIT " . $start . " OFFSET " . $offset; return $this; } // + tons of other overrides... } function clientCode(SQLQueryBuilder $queryBuilder) { // ... $query = $queryBuilder ->select("users", ["name", "email", "password"]) ->where("age", 18, ">") ->where("age", 30, "<") ->limit(10, 20) ->getSQL(); echo $query; // ... } if (isset($_ENV['database_type']) && $_ENV['database_type'] == 'postgres') { $builder = new PostgresQueryBuilder(); } else { $builder = new MysqlQueryBuilder(); } clientCode($builder); ``` </details> <br /> 输出 ``` SELECT name, email, password FROM users WHERE age > '18' AND age < '30' LIMIT 10, 20;% ```