simple-factory Проста Фабрика (англ. Simple Factory) дозволяє створювати об’єкти без логіки їх створення у клієнті. Сам собою не є шаблоном. Підхід, у якому логіка створення об’єктів виноситься у окремий клас.

Плюси

  • Дозволяє дотримуватися принципу DRY (логіка створення об’єкта описується всього один раз, надалі клієнти просто викликають методи фабрики).
  • Клієнти перестають бути сильно пов’язані з конкретними реалізаціями продуктів.
  • Дозволяє швидко змінити логіку створення об’єктів і конкретні реалізації об’єктів, що повертаються.

Візьмемо наш приклад із Фабричного методу. Наш кухар реалізовував інтерфейс, завдяки якому, як нам відомо, кухар уміє готувати бургери. Суть простої фабрики в тому, що у нас є клас кухаря(Chief), який вміє готувати бургери. Може бути інший клас кухаря, який, наприклад, готуватиме піцу. Цей кухар буде вже іншою простою фабрикою. Як бачимо, приклад майже не відрізняється від Фабричного методу, крім реалізації інтерфейсу.

  • Burgers
    • Burger.php
                    
      <?php
      
      namespace DesignPatterns\Creational\SimpleFactory\Burgers;
      
      /**
       * Class Burger
       * @package DesignPatterns\Creational\SimpleFactory\Burgers
       */
      abstract class Burger
      {
          /**
           * @var string
           */
          protected $meat;
      
          /**
           * @var string
           */
          protected $sauce;
      
          /**
           * @var bool
           */
          protected $withCheese;
      
          /**
           * @return string
           */
          public function getMeat(): string
          {
              return $this->meat;
          }
      
          /**
           * @param string $meat
           *
           * @return void
           */
          public function setMeat(string $meat)
          {
              $this->meat = $meat;
          }
      
          /**
           * @return string
           */
          public function getSauce(): string
          {
              return $this->sauce;
          }
      
          /**
           * @param string $sauce
           *
           * @return void
           */
          public function setSauce(string $sauce)
          {
              $this->sauce = $sauce;
          }
      
          /**
           * @return bool
           */
          public function getWithCheese(): bool
          {
              return $this->withCheese;
          }
      
          /**
           * @param bool $withCheese
           *
           * @return void
           */
          public function setWithCheese(bool $withCheese)
          {
              $this->withCheese = $withCheese;
          }
      }
      
                    
    • Cheeseburger.php
                    
      <?php
      
      namespace DesignPatterns\Creational\SimpleFactory\Burgers;
      
      /**
       * Class Cheeseburger
       * @package DesignPatterns\Creational\SimpleFactory\Burgers
       */
      class Cheeseburger extends Burger
      {
          /**
           * @var string
           */
          protected $meat = 'chicken';
      
          /**
           * @var string
           */
          protected $sauce = 'mayonnaise';
      
          /**
           * @var bool
           */
          protected $withCheese = true;
      }
      
                    
    • Hamburger.php
                    
      <?php
      
      namespace DesignPatterns\Creational\SimpleFactory\Burgers;
      
      /**
       * Class Hamburger
       * @package DesignPatterns\Creational\SimpleFactory\Burgers
       */
      class Hamburger extends Burger
      {
          /**
           * @var string
           */
          protected $meat = 'beef';
      
          /**
           * @var string
           */
          protected $sauce = 'ketchup';
      
          /**
           * @var bool
           */
          protected $withCheese = false;
      }
      
                    
  • Chef.php
                  
    <?php
    
    namespace DesignPatterns\Creational\SimpleFactory;
    
    use DesignPatterns\Creational\SimpleFactory\Burgers\Burger;
    use DesignPatterns\Creational\SimpleFactory\Burgers\Hamburger;
    use DesignPatterns\Creational\SimpleFactory\Burgers\Cheeseburger;
    
    /**
     * Class Chef
     * @package DesignPatterns\Creational\SimpleFactory
     */
    class Chef
    {
        /**
         * @param string $typeBurger
         *
         * @return Burger
         */
        public function makeBurger(string $typeBurger): Burger
        {
            $typeBurger = strtolower($typeBurger);
    
            switch ($typeBurger) {
                case 'cheeseburger':
                    return new Cheeseburger();
                case 'hamburger':
                    return new Hamburger();
                default:
                    throw new \InvalidArgumentException('Sorry. But we haven\'t this burger.');
            }
        }
    }
    
                  
  • Test case:

    SimpleFactoryTest.php
      
    <?php
    
    namespace DesignPatterns\Tests\Creational\SimpleFactory;
    
    use DesignPatterns\Creational\SimpleFactory\Chef;
    use InvalidArgumentException;
    use PHPUnit_Framework_TestCase;
    
    class SimpleFactoryTest extends PHPUnit_Framework_TestCase
    {
        public function testHamburgerInstanceOfBurger()
        {
            $chef = new Chef();
    
            $hamburger = $chef->makeBurger('hamburger');
            $someHamburger = $chef->makeBurger('hamburger');
    
            $this->assertInstanceOf('DesignPatterns\Creational\SimpleFactory\Burgers\Burger', $hamburger);
            $this->assertInstanceOf('DesignPatterns\Creational\SimpleFactory\Burgers\Burger', $someHamburger);
            $this->assertNotSame($hamburger, $someHamburger);
        }
    
        public function testCheeseburgerInstanceOfBurger()
        {
            $chef = new Chef();
    
            $cheeseburger = $chef->makeBurger('cheeseburger');
            $someCheeseburger = $chef->makeBurger('cheeseburger');
    
            $this->assertInstanceOf('DesignPatterns\Creational\SimpleFactory\Burgers\Burger', $cheeseburger);
            $this->assertInstanceOf('DesignPatterns\Creational\SimpleFactory\Burgers\Burger', $someCheeseburger);
            $this->assertNotSame($cheeseburger, $someCheeseburger);
        }
    
        public function testException()
        {
            $this->expectException(InvalidArgumentException::class);
            $chef = new Chef();
    
            $chef->makeBurger('someNameForBurger');
        }
    
        public function testHamburgerСomposition()
        {
            $chef = new Chef();
    
            $hamburger = $chef->makeBurger('hamburger');
    
            $hamburgerMeat = $hamburger->getMeat();
            $hamburgerSauce = $hamburger->getSauce();
            $hamburgerWithCheese = $hamburger->getWithCheese();
    
            $this->assertEquals('beef', $hamburgerMeat);
            $this->assertNotEquals('chicken', $hamburgerMeat);
    
            $this->assertEquals('ketchup', $hamburgerSauce);
            $this->assertNotEquals('mayonnaise', $hamburgerSauce);
    
            $this->assertEquals(false, $hamburgerWithCheese);
            $this->assertNotEquals(true, $hamburgerWithCheese);
        }
    
        public function testCheeseburgerСomposition()
        {
            $chef = new Chef();
    
            $cheeseburger = $chef->makeBurger('cheeseburger');
    
            $cheeseburgerMeat = $cheeseburger->getMeat();
            $cheeseburgerSauce = $cheeseburger->getSauce();
            $cheeseburgerWithCheese = $cheeseburger->getWithCheese();
    
            $this->assertEquals('chicken', $cheeseburgerMeat);
            $this->assertNotEquals('beef', $cheeseburgerMeat);
    
            $this->assertEquals('mayonnaise', $cheeseburgerSauce);
            $this->assertNotEquals('ketchup', $cheeseburgerSauce);
    
            $this->assertEquals(true, $cheeseburgerWithCheese);
            $this->assertNotEquals(false, $cheeseburgerWithCheese);
        }
    }