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