builder Строитель (англ. Builder) — это интерфейс для инкапсулирования механизма создания сложного объекта. Суть его заключается в том, чтобы отделить процесс создания некоторого сложного объекта от его представления. Таким образом, можно получать различные представления объекта, используя один и тот же “технологический” процесс. Данный шаблон очень тесно переплетается с шаблоном Фабрика.

Применение:

  • алгоритм создания сложного объекта не должен зависеть от того, из каких частей состоит объект и как они стыкуются между собой;
  • процесс конструирования должен обеспечивать различные представления конструируемого объекта.

Раньше мы создавали наши бургеры уже из готовых классов. Что бы показать работу этого шаблона мы изменим создание бургеров. Разобьём весь бургер на части и потом с помощью билдера соберём тот, который нам нужен. В этом примере билдеры - это своего рода рецепты, которые мы передали повару. А повар в свою очередь, как с ним обращаться.

Примеры:

  • PHPUnit: Mock Builder
  • Builders
    • BurgerBuilderInterface.php
                    
      <?php
      
      namespace DesignPatterns\Creational\Builder\Builders;
      
      use DesignPatterns\Creational\Builder\Burger\AbstractBurger;
      
      /**
       * Interface BurgerBuilderInterface
       * @package DesignPatterns\Creational\Builder\Builders
       */
      interface BurgerBuilderInterface
      {
          /**
           * @return void
           */
          public function createBurger();
      
          /**
           * @return AbstractBurger
           */
          public function getBurger(): AbstractBurger;
      
          /**
           * @return void
           */
          public function addSauce();
      
          /**
           * @return void
           */
          public function addMeat();
      
          /**
           * @return void
           */
          public function addMuffin();
      }
      
                    
    • CheeseburgerBuilder.php
                    
      <?php
      
      namespace DesignPatterns\Creational\Builder\Builders;
      
      use DesignPatterns\Creational\Builder\Burger\AbstractBurger;
      use DesignPatterns\Creational\Builder\Burger\Burger;
      use DesignPatterns\Creational\Builder\Burger\Parts\Meat;
      use DesignPatterns\Creational\Builder\Burger\Parts\Muffin;
      use DesignPatterns\Creational\Builder\Burger\Parts\Sauce;
      
      /**
       * Class CheeseburgerBuilder
       * @package DesignPatterns\Creational\Builder\Builders
       */
      class CheeseburgerBuilder implements BurgerBuilderInterface
      {
          /**
           * @var AbstractBurger
           */
          private $cheeseburger;
      
          /**
           * @return void
           */
          public function createBurger()
          {
              $this->cheeseburger = new Burger();
          }
      
          /**
           * @return AbstractBurger
           */
          public function getBurger(): AbstractBurger
          {
              return $this->cheeseburger;
          }
      
          /**
           * @return void
           */
          public function addSauce()
          {
              $this->cheeseburger->setBurgerParts('sauce', new Sauce('mayonnaise'));
          }
      
          /**
           * @return void
           */
          public function addMeat()
          {
              $this->cheeseburger->setBurgerParts('meet', new Meat('chicken'));
          }
      
          /**
           * @return void
           */
          public function addMuffin()
          {
              $this->cheeseburger->setBurgerParts('muffin', new Muffin('muffin'));
          }
      }
      
                    
    • HamburgerBuilder.php
                    
      <?php
      
      namespace DesignPatterns\Creational\Builder\Builders;
      
      use DesignPatterns\Creational\Builder\Burger\AbstractBurger;
      use DesignPatterns\Creational\Builder\Burger\Burger;
      use DesignPatterns\Creational\Builder\Burger\Parts\Meat;
      use DesignPatterns\Creational\Builder\Burger\Parts\Muffin;
      use DesignPatterns\Creational\Builder\Burger\Parts\Sauce;
      
      /**
       * Class HamburgerBuilder
       * @package DesignPatterns\Creational\Builder\Builders
       */
      class HamburgerBuilder implements BurgerBuilderInterface
      {
          /**
           * @var AbstractBurger
           */
          private $hamburger;
      
          /**
           * @return void
           */
          public function createBurger()
          {
              $this->hamburger = new Burger();
          }
      
          /**
           * @return AbstractBurger
           */
          public function getBurger(): AbstractBurger
          {
              return $this->hamburger;
          }
      
          /**
           * @return void
           */
          public function addSauce()
          {
              $this->hamburger->setBurgerParts('sauce', new Sauce('Ketchup'));
          }
      
          /**
           * @return void
           */
          public function addMeat()
          {
              $this->hamburger->setBurgerParts('meet', new Meat('beef'));
          }
      
          /**
           * @return void
           */
          public function addMuffin()
          {
              $this->hamburger->setBurgerParts('muffin', new Muffin('muffin'));
          }
      }
      
                    
  • Burger
      Parts
      • AbstractPart.php
                              
        <?php
        
        namespace DesignPatterns\Creational\Builder\Burger\Parts;
        
        /**
         * Class AbstractPart
         * @package DesignPatterns\Creational\Builder\Burger\Parts
         */
        abstract class AbstractPart
        {
            /**
             * @var string
             */
            protected $title;
        
            /**
             * AbstractPart constructor.
             *
             * @param string $title
             */
            public function __construct(string $title)
            {
                $this->title = $title;
            }
        
            /**
             * @return string
             */
            public function getTitle(): string
            {
                return $this->title;
            }
        }
        
                              
      • Meat.php
                              
        <?php
        
        namespace DesignPatterns\Creational\Builder\Burger\Parts;
        
        /**
         * Class Meat
         * @package DesignPatterns\Creational\Builder\Burger\Parts
         */
        class Meat extends AbstractPart
        {
        }
        
                              
      • Muffin.php
                              
        <?php
        
        namespace DesignPatterns\Creational\Builder\Burger\Parts;
        
        /**
         * Class Muffin
         * @package DesignPatterns\Creational\Builder\Burger\Parts
         */
        class Muffin extends AbstractPart
        {
        }
        
                              
      • Sauce.php
                              
        <?php
        
        namespace DesignPatterns\Creational\Builder\Burger\Parts;
        
        /**
         * Class Sauce
         * @package DesignPatterns\Creational\Builder\Burger\Parts
         */
        class Sauce extends AbstractPart
        {
        }
        
                              
    • AbstractBurger.php
                    
      <?php
      
      namespace DesignPatterns\Creational\Builder\Burger;
      
      use DesignPatterns\Creational\Builder\Burger\Parts\AbstractPart;
      
      /**
       * Class AbstractBurger
       * @package DesignPatterns\Creational\Builder\Burger
       */
      abstract class AbstractBurger
      {
          /**
           * @var AbstractPart[]
           */
          private $burgerParts = [];
      
          /**
           * @param string $partName
           * @param AbstractPart $partObject
           *
           * @return void
           */
          public function setBurgerParts(string $partName, AbstractPart $partObject)
          {
              $this->burgerParts[$partName] = $partObject;
          }
      }
      
                    
  • Director
    • Chef.php
                    
      <?php
      
      namespace DesignPatterns\Creational\Builder\Director;
      
      use DesignPatterns\Creational\Builder\Builders\BurgerBuilderInterface;
      use DesignPatterns\Creational\Builder\Burger\AbstractBurger;
      
      /**
       * Class Chef
       * @package DesignPatterns\Creational\Builder\Director
       */
      class Chef implements DirectorInterface
      {
          /**
           * @param BurgerBuilderInterface $builder
           *
           * @return AbstractBurger
           */
          public function buildBurger(BurgerBuilderInterface $builder): AbstractBurger
          {
              $builder->createBurger();
              $builder->addMeat();
              $builder->addSauce();
              $builder->addMuffin();
      
              return $builder->getBurger();
          }
      }
      
                    
    • DirectorInterface.php
                    
      <?php
      
      namespace DesignPatterns\Creational\Builder\Director;
      
      use DesignPatterns\Creational\Builder\Builders\BurgerBuilderInterface;
      use DesignPatterns\Creational\Builder\Burger\AbstractBurger;
      
      /**
       * Interface DirectorInterface
       * @package DesignPatterns\Creational\Builder\Director
       */
      interface DirectorInterface
      {
          /**
           * @param BurgerBuilderInterface $builder
           *
           * @return AbstractBurger
           */
          public function buildBurger(BurgerBuilderInterface $builder): AbstractBurger;
      }
      
                    

    Test case:

    BuilderTest.php
      
    <?php
    namespace DesignPatterns\Tests\Creational\Builder;
    
    use DesignPatterns\Creational\Builder\Builders\CheeseburgerBuilder;
    use DesignPatterns\Creational\Builder\Builders\HamburgerBuilder;
    use DesignPatterns\Creational\Builder\Director\Chef;
    
    class BuilderTest extends \PHPUnit_Framework_TestCase
    {
        /**
         * @var Chef
         */
        private $chef;
    
        protected function setUp(): void
        {
            $this->chef = new Chef();
        }
    
        public function testCanCreateHamburger()
        {
            $builder = new HamburgerBuilder();
    
            $hamburger = $this->chef->buildBurger($builder);
    
            $this->assertInstanceOf('DesignPatterns\Creational\Builder\Burger\Burger', $hamburger);
        }
    
        public function testCanCreateCheeseburger()
        {
            $builder = new CheeseburgerBuilder();
    
            $cheeseburger = $this->chef->buildBurger($builder);
    
            $this->assertInstanceOf('DesignPatterns\Creational\Builder\Burger\Burger', $cheeseburger);
        }
    }