简介
建造者模式可将对象的初始化转变成一步步配置的过程。如当对象的初始化时有很多可选参数,建造者模式能够定制参数实现对象的创立。益处有:
- 定制对象参数
- 针对不同参数,做不同的校验,如当设置了三角形的两个边长,设置第三个边时必须满足两边之和大于第三边的条件。
角色
-
Builder 类
定义建造一个 Product 分几个步骤
-
具体 Builder 类
实现不同的步骤
-
Director
属于疾速建造某一种产品的办法,如 Director 提供了创立自动挡和手动挡汽车两种办法,创立自动挡汽车中其实是调用 setA setB,而创立主动单汽车中调用 setC setD。也能够不应用 Director,间接应用 Builder 的 setA setB 去设置属性
-
要被实例化的类
初始化时可定制的参数较多,如 setA setB setC…
类图
图中的 Director 在 make 办法中封装了设置产品属性的步骤,通过传入不同的 builder 类,实现不同的实现步骤,创立不同的产品。
代码
interface Builder
{public function producePartA(): void;
public function producePartB(): void;
public function producePartC(): void;}
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;
}
}
/**
* EN: It makes sense to use the Builder pattern only when your products are
* quite complex and require extensive configuration.
*
* Unlike in other creational patterns, different concrete builders can produce
* unrelated products. In other words, results of various builders may not
* always follow the same interface.
*
* RU: Имеет смысл использовать паттерн Строитель только тогда, когда ваши
* продукты достаточно сложны и требуют обширной конфигурации.
*
* В отличие от других порождающих паттернов, различные конкретные строители
* могут производить несвязанные продукты. Другими словами, результаты различных
* строителей могут не всегда следовать одному и тому же интерфейсу.
*/
class Product1
{public $parts = [];
public function listParts(): void
{echo "Product parts:" . implode(',', $this->parts) . "\n\n";
}
}
class Director
{
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();}
}
function clientCode(Director $director)
{$builder = new ConcreteBuilder1();
$director->setBuilder($builder);
echo "Standard basic product:\n";
$director->buildMinimalViableProduct();
$builder->getProduct()->listParts();
echo "Standard full featured product:\n";
$director->buildFullFeaturedProduct();
$builder->getProduct()->listParts();
// 不应用 Director,间接操作 builder 来创立产品
echo "Custom product:\n";
$builder->producePartA();
$builder->producePartC();
$builder->getProduct()->listParts();
}
$director = new Director();
clientCode($director);
output:
Standard basic product:
Product parts: PartA1
Standard full featured product:
Product parts: PartA1, PartB1, PartC1
Custom product:
Product parts: PartA1, PartC1