fluent-interface Текучий интерфейс (англ. Fluent interface) — способ реализации в разработке программного обеспечения, объектно-ориентированного API, нацеленный на повышение читабельности исходного кода программы.

Текучий интерфейс хорош тем, что упрощается множественный вызов методов одного объекта. Обычно это реализуется использованием цепочки методов, передающих контекст вызова следующему звену.

Тут всё очень просто. Благодаря данному шаблону мы можем делать бургер через цепочку вызовов, а не каждый раз вызывать новый метод.

  • BurgerMaker.php
                  
    <?php
    
    namespace DesignPatterns\Structural\FluentInterface;
    
    /**
     * Class BurgerMaker
     * @package DesignPatterns\Structural\FluentInterface
     */
    class BurgerMaker
    {
        /**
         * @var string
         */
        public $muffin;
    
        /**
         * @var string
         */
        public $sauce;
    
        /**
         * @var string
         */
        public $meat;
    
        /**
         * @var string
         */
        public $cheese;
    
        /**
         * @param string $muffin
         *
         * @return BurgerMaker
         */
        public function setMuffin($muffin): BurgerMaker
        {
            $this->muffin = $muffin;
    
            return $this;
        }
    
        /**
         * @param string $sauce
         *
         * @return BurgerMaker
         */
        public function setSauce($sauce)
        {
            $this->sauce = $sauce;
    
            return $this;
        }
    
        /**
         * @param string $meat
         *
         * @return BurgerMaker
         */
        public function setMeat($meat)
        {
            $this->meat = $meat;
    
            return $this;
        }
    
        /**
         * @param string $cheese
         *
         * @return BurgerMaker
         */
        public function setCheese($cheese)
        {
            $this->cheese = $cheese;
    
            return $this;
        }
    
        /**
         * @return array
         */
        public function getBurger(): array
        {
            $burger = [];
    
            foreach ($this as $valName => $val) {
                if ($val) {
                    $burger[$valName] = $val;
                }
            }
    
            $this->clearWorkbench();
    
            return $burger;
        }
    
        /**
         * @return void
         */
        protected function clearWorkbench()
        {
            foreach ($this as $valName => $val) {
                $this->$valName = null;
            }
        }
    }
    
                  
  • Test case:

    BurgerMakerTest.php
      
    <?php
    
    namespace DesignPatterns\Tests\Structural\FluentInterface;
    
    use DesignPatterns\Structural\FluentInterface\BurgerMaker;
    use PHPUnit_Framework_TestCase;
    
    class BurgerMakerTest extends PHPUnit_Framework_TestCase
    {
        /**
         * @var BurgerMaker
         */
        protected static $burgerMaker;
    
        public static function setUpBeforeClass(): void
        {
            self::$burgerMaker = new BurgerMaker();
        }
    
        public function testBurgerSetMuffin()
        {
            $this->assertEquals(null, self::$burgerMaker->muffin);
    
            $maker = self::$burgerMaker->setMuffin('muffin');
    
            $this->assertEquals('muffin', self::$burgerMaker->muffin);
            $this->assertSame(self::$burgerMaker, $maker);
        }
    
        public function testBurgerSetSauce()
        {
            $this->assertEquals(null, self::$burgerMaker->sauce);
    
            $maker = self::$burgerMaker->setSauce('ketchup');
    
            $this->assertEquals('ketchup', self::$burgerMaker->sauce);
            $this->assertSame(self::$burgerMaker, $maker);
        }
    
        public function testBurgerSetMeat()
        {
            $this->assertEquals(null, self::$burgerMaker->meat);
    
            $maker = self::$burgerMaker->setMeat('beef');
    
            $this->assertEquals('beef', self::$burgerMaker->meat);
            $this->assertSame(self::$burgerMaker, $maker);
        }
    
        public function testBurgerSetCheese()
        {
            $this->assertEquals(null, self::$burgerMaker->cheese);
    
            $maker = self::$burgerMaker->setCheese('cheddar');
    
            $this->assertEquals('cheddar', self::$burgerMaker->cheese);
            $this->assertSame(self::$burgerMaker, $maker);
        }
    
        public function testBurgerGetBurger()
        {
            $this->assertEquals('muffin', self::$burgerMaker->muffin);
            $this->assertEquals('ketchup', self::$burgerMaker->sauce);
            $this->assertEquals('beef', self::$burgerMaker->meat);
            $this->assertEquals('cheddar', self::$burgerMaker->cheese);
    
            $burger = self::$burgerMaker
                ->setMuffin('muffin')
                ->setSauce('sauce')
                ->setMeat('meat')
                ->setCheese('cheese')
                ->getBurger();
    
            $this->assertArrayHasKey('muffin', $burger);
            $this->assertArrayHasKey('sauce', $burger);
            $this->assertArrayHasKey('meat', $burger);
            $this->assertArrayHasKey('cheese', $burger);
    
            $this->assertEquals('muffin', $burger['muffin']);
            $this->assertEquals('sauce', $burger['sauce']);
            $this->assertEquals('meat', $burger['meat']);
            $this->assertEquals('cheese', $burger['cheese']);
    
            $this->assertEquals(null, self::$burgerMaker->muffin);
            $this->assertEquals(null, self::$burgerMaker->sauce);
            $this->assertEquals(null, self::$burgerMaker->meat);
            $this->assertEquals(null, self::$burgerMaker->cheese);
        }
    }