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);
        }
    }