建造者模式,也可以叫做生成器模式,builder這個詞的原意就包含了建筑者、開發者、創建者的含義,很明顯,這個模式又是一個創建型的模式,用來創建物件,那么它的特點是什么呢?從建筑上來說,蓋房子不是一下子就馬上能把一個房子蓋好的,而是通過一磚一瓦搭建出來的,一個房子不僅有磚瓦,還有各種管道,各種電線等等,由它們各個不部分共同組成了一棟房子,可以說,建造者模式就是這樣非常形象的由各種部件來組成一個物件(房子)的程序,
Gof類圖及解釋
GoF定義:將一個復雜物件的構建與它的表示分離,使得同樣的構建程序可以創建不同的表示
GoF類圖

代碼實作
class Product
{
private $parts = [];
public function Add(String $part): void
{
$this->parts[] = $part;
}
public function Show(): void
{
echo PHP_EOL . '產品創建 ----', PHP_EOL;
foreach ($this->parts as $part) {
echo $part, PHP_EOL;
}
}
}
產品類,你可以把它想象成我們要建造的房子,這時的房子還沒有任何內容,我們需要給它添磚加瓦,
interface Builder
{
public function BuildPartA(): void;
public function BuildPartB(): void;
public function GetResult(): Product;
}
class ConcreteBuilder1 implements Builder
{
private $product;
public function __construct()
{
$this->product = new Product();
}
public function BuildPartA(): void
{
$this->product->Add('部件A');
}
public function BuildPartB(): void
{
$this->product->Add('部件B');
}
public function GetResult(): Product
{
return $this->product;
}
}
class ConcreteBuilder2 implements Builder
{
private $product;
public function __construct()
{
$this->product = new Product();
}
public function BuildPartA(): void
{
$this->product->Add('部件X');
}
public function BuildPartB(): void
{
$this->product->Add('部件Y');
}
public function GetResult(): Product
{
return $this->product;
}
}
建造者抽象及其實作,不同的開發商總會選用不同的品牌材料,這里我們有了兩個不同的開發商,但他們的目的一致,都是為了去蓋房子(Product),
class Director
{
public function Construct(Builder $builder)
{
$builder->BuildPartA();
$builder->BuildPartB();
}
}
構造器,用來呼叫建造者進行生產,沒錯,就是我們的工程隊,它來選取材料并進行建造,同樣的工程隊,可以接不同的單,但蓋出來的都是房子,只是這個房子的材料和外觀不同,大體上的手葉訓是共通的,
$director = new Director();
$b1 = new ConcreteBuilder1();
$b2 = new ConcreteBuilder2();
$director->Construct($b1);
$p1 = $b1->getResult();
$p1->Show();
$director->Construct($b2);
$p2 = $b2->getResult();
$p2->Show();
最后看看我們的實作,是不是非常簡單,準備好工程隊,準備好不同的建造者,然后交給工程隊去生產就好啦!!
- 其實這個模式要解決的最主要問題就是一個類可能有非常多的配置、屬性,這些配置、屬性也并不全是必須要配置的,一次性的實體化去配置這些東西非常麻煩,這時就可以考慮讓這些配置、屬性變成一個一個可隨時添加的部分,通過不同的屬性組合拿到不同的物件,
- 上面那一條,在GoF那里的原文是:它使你改變一個產品的內部表示;它將構造代碼和表示代碼分開;它使你可以對構造程序進行更精細的控制,
- 再說得簡單一點,物件太復雜,我們可以一部分一部分的拼裝它!
- 了解過一點Android開發的一定不會陌生,創建對話框物件AlterDialog.builder
- Laravel中,資料庫組件也使用了建造者模式,你可以翻看下原始碼中Database\Eloquent和Database\Query目錄中是否都有一個Builder.php
大家都知道,手機組裝是一件復雜的程序,于是,不同型號的手機我們都有對應的圖紙(Builder),將圖紙和配件交給流水線上的工人(Director),他們就會根據圖紙使用配件來生產出我們所需要的各種不同型號的手機(Product),很明顯,我們都是偉大的建造者,為我們的產業添磚加瓦!!!
完整代碼:https://github.com/zhangyue0503/designpatterns-php/blob/master/16.builder/source/builder.php
實體
前面說過Android中有很多Dialog對話框都會用建造者模式來實作,作為一家手機廠的老板,定制化的Android系統也是非常重要的一個部分,就像X米一樣,從MIUI入手,先拿下了軟體市場,讓大家覺得這個系統非常好用,然后再開始開發手機,這就說明軟硬體的確是現代手機的兩大最重要的組成部分,缺了誰都不行,這回,我們就用建造者模式簡單的實作一套對話框組件吧!
對話框類圖

完整原始碼:https://github.com/zhangyue0503/designpatterns-php/blob/master/16.builder/source/builder-dialog.php
<?php
class Dialog
{
private $attributes = [];
private $buttons = [];
private $title = '';
private $content = '';
public function AddAttributes($attr)
{
$this->attributes[] = $attr;
}
public function AddButtons($button)
{
$this->buttons[] = $button;
}
public function SetTitle($title)
{
$this->title = $title;
}
public function SetContent($content)
{
$this->content = $content;
}
public function ShowDialog(){
echo PHP_EOL, '顯示提示框 === ', PHP_EOL;
echo '標題:' . $this->title, PHP_EOL;
echo '內容:' . $this->content, PHP_EOL;
echo '樣式:' . implode(',', $this->attributes), PHP_EOL;
echo '按扭:' . implode(',', $this->buttons), PHP_EOL;
}
}
interface Builder
{
public function BuildAttribute($attr);
public function BuildButton($button);
public function BuildTitle($title);
public function BuildContent($content);
public function GetDialog();
}
class DialogBuilder implements Builder{
private $dialog;
public function __construct(){
$this->dialog = new Dialog();
}
public function BuildAttribute($attr){
$this->dialog->AddAttributes($attr);
}
public function BuildButton($button){
$this->dialog->AddButtons($button);
}
public function BuildTitle($title){
$this->dialog->SetTitle($title);
}
public function BuildContent($content){
$this->dialog->SetContent($content);
}
public function GetDialog(){
return $this->dialog;
}
}
class DialogDirector {
public function Construct($title, $content){
$builder = new DialogBuilder();
$builder->BuildAttribute('置于頂層');
$builder->BuildAttribute('居中顯示');
$builder->BuildButton('確認');
$builder->BuildButton('取消');
$builder->BuildTitle($title);
$builder->BuildContent($content);
return $builder;
}
}
class ModalDialogDirector {
public function Construct($title, $content){
$builder = new DialogBuilder();
$builder->BuildAttribute('置于頂層');
$builder->BuildAttribute('居中顯示');
$builder->BuildAttribute('背景庶照');
$builder->BuildAttribute('外部無法點擊');
$builder->BuildButton('確認');
$builder->BuildButton('取消');
$builder->BuildTitle($title);
$builder->BuildContent($content);
return $builder;
}
}
$d1 = new DialogDirector();
$d1->Construct('視窗1', '確認要執行操作A嗎?')->GetDialog()->ShowDialog();
$d2 = new ModalDialogDirector();
$d2->Construct('視窗2', '確認要執行操作B嗎?')->GetDialog()->ShowDialog();
說明
- 這回我們的產品就有點復雜了,有標題、內容、屬性、按扭等
- 建造程序其實都一樣,但這里我們主要使用了不同的構造器,普通對話框外面的東西是可以點擊的,而模態視窗一般會有遮罩層,就是背景變成透明黑,而且外面的東西是不能再點擊的
- 如果每次都直接通過構造方法去實體化視窗類,那要傳遞的引數會很多,而現在這樣,我們就可以通過建造者來進行組合,讓物件具有多型的效果,能夠呈現不同的形態及功能
下期看點
建造者模式真的非常常用,雖說我們平常寫的代碼中可能用得比較少,但在很多框架或者大型系統的架構中都會有它的身影,我們希望類都是簡單的,小巧的,但大型類的出現總是不可避免的,這個時候,建造者模式就能發揮它的作用,讓我們能夠輕松的構建復雜、大型的物件,好吧,不要忘了我們的文章還在繼續,如果喜歡的話要記得關注公眾號或者掘金主頁哦,如果怕忘了,不妨寫個備忘錄哦,
關注公眾號:【硬核專案經理】獲取最新文章
添加微信/QQ好友:【xiaoyuezigonggong/149844827】免費得PHP、專案管理學習資料
知乎、公眾號、抖音、頭條搜索【硬核專案經理】
B站ID:482780532
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/242205.html
標籤:PHP
