05 02 2020

建造者模式

模式定义

将一个复杂对象的建造与调用者分离。调用者只需要给出指定对象的类型和内容,建造者模式负责按照顺寻创建复杂对象.


建造者模式的优势

易于解耦,将产品本身与创建的过程分离,可以使用相同的创建过程来创建不同的产品. 易于精确的控制对象,将复杂对象的创建划分在不同的方法中,创建过程更加清晰 易于扩展,增加新的建造者无需修改原来的类库

建造者模式的缺陷

建造者模式的产品具有较多的共同点,组成部分类似。如果产品之间差异较大,则不适合 如果产品的内部变化复杂,需要定义更多具体的建造者来配合,导致系统变的庞大

代码示例

Builder\Director.class.php
<?php
namespace Builder;

class Director
{
    public function build($builder)
    {
        $builder->createVehicle();
        $builder->addDoors();
        $builder->addEngine();
        $builder->addWheel();

        return $builder->getVehicle();
    }
}


Builder\BuilderInterface.class.php
<?php
namespace Builder;

interface BuilderInterface
{
    public function createVehicle();

    public function addDoors();

    public function addEngine();

    public function addWheel();

    public function getVehicle();
}


Builder\BikeBuilder.class.php
<?php
namespace Builder;

use Builder\Parts\Bike;
use Builder\Parts\Wheel;
use Builder\Parts\Engine;

class BikeBuilder implements BuilderInterface
{
    protected $bike;

    public function createVehicle()
    {
        $this->bike = new Bike();
    }

    public function addWheel()
    {
        $this->bike->setPart('forwardWheel', new Wheel());
        $this->bike->setPart('rearWheel', new Wheel());
    }

    public function addEngine()
    {
        $this->bike->setPart('engine', new Engine());
    }

    public function addDoors()
    {

    }

    public function getVehicle()
    {
        return $this->bike;
    }
}


Builder\CarBuilder.class.php
<?php
namespace Builder;

use Builder\Parts\Door;
use Builder\Parts\Engine;
use Builder\Parts\Wheel;
use Builder\Parts\Car;

class CarBuilder implements BuilderInterface
{
    protected $car;

    public function createVehicle()
    {
        $this->car = new Car();
    }

    public function addWheel()
    {
        $this->car->setPart('wheelLF', new Wheel());
        $this->car->setPart('wheelRF', new Wheel());
        $this->car->setPart('wheelLR', new Wheel());
        $this->car->setPart('wheelRR', new Wheel());
    }

    public function addEngine()
    {
        $this->car->setPart('engine', new Engine());
    }

    public function addDoors()
    {
        $this->car->setPart('rightdoor', new Door());
        $this->car->setPart('leftdoor', new Door());
    }

    public function getVehicle()
    {
        return $this->car;
    }
}


Builder\Parts\Vehicle.class.php
<?php
namespace Builder\Parts;

abstract class Vehicle
{
    protected $data;

    public function setPart($key, $value)
    {
        $this->data[$key] = $value;
    }
}


Builder\Parts\Bike.class.php
<?php
namespace Builder\Parts;

class Bike extends Vehicle
{

}


Builder\Parts\Car.class.php
<?php
namespace Builder\Parts;

class Car extends Vehicle
{

}


Builder\Parts\Door.class.php
<?php
namespace Builder\Parts;

class Door
{

}


Builder\Parts\Engine.class.php
<?php
namespace Builder\Parts;

class Engine
{

}


Builder\Parts\Wheel.class.php
<?php
namespace Builder\Parts;

class Wheel
{

}


Builder\BuilderTest.php
<?php
spl_autoload_register(function ($className){
   $className = str_replace("\\", "/", $className);
   include $className . ".class.php";
});

use Builder\Director;
use Builder\BikeBuilder;
use Builder\CarBuilder;

$director = new Director();
$bike = $director->build(new BikeBuilder());
$car = $director->build(new CarBuilder());

var_dump($bike);
var_dump($car);


测试示例:

php Builder/BuilderTest.php

输出:
object(Builder\Parts\Bike)#4 (1) {
  ["data":protected]=>
  array(3) {
    ["engine"]=>
    object(Builder\Parts\Engine)#5 (0) {
    }
    ["forwardWheel"]=>
    object(Builder\Parts\Wheel)#6 (0) {
    }
    ["rearWheel"]=>
    object(Builder\Parts\Wheel)#7 (0) {
    }
  }
}
object(Builder\Parts\Car)#8 (1) {
  ["data":protected]=>
  array(7) {
    ["rightdoor"]=>
    object(Builder\Parts\Door)#9 (0) {
    }
    ["leftdoor"]=>
    object(Builder\Parts\Door)#10 (0) {
    }
    ["engine"]=>
    object(Builder\Parts\Engine)#11 (0) {
    }
    ["wheelLF"]=>
    object(Builder\Parts\Wheel)#12 (0) {
    }
    ["wheelRF"]=>
    object(Builder\Parts\Wheel)#13 (0) {
    }
    ["wheelLR"]=>
    object(Builder\Parts\Wheel)#14 (0) {
    }
    ["wheelRR"]=>
    object(Builder\Parts\Wheel)#15 (0) {
    }
  }
}


总结

建造者模式和抽象工厂模式很像,总体上,建造者模式仅仅只比抽象工厂模式多了一个“导演类”的角色。与抽象工厂模式相比,建造者模式一般用来创建更为复杂的对象,因为对象的创建过程更为复杂,因此将对象的创建过程独立出来组成一个新的类 —— 导演类。也就是说,抽像工厂模式是将对象的全部创建过程封装在工厂类中,由工厂类向客户端提供最终的产品;而建造者模式中,建造者类一般只提供产品类中各个组件的建造,而将完整建造过程交付给导演类。由导演类负责将各个组件按照特定的规则组建为产品,然后将组建好的产品交付给客户端。



代码地址:https://github.com/798256478/design-patterns/tree/master/Builder