visitor Посетитель (англ. Visitor) — поведенческий шаблон проектирования, основным назначением которого является добавление доп. функционала для объектов разных классов, не изменяя их. Для этого данный функционал переноситься в сам класс Посетителя.

Применение:

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

  • Посетитель позволяет добавить одну и ту же операцию в различные типы объектов, которые он посещает.

  • Над объектами, входящими в состав структуры, надо выполнять разнообразные, не связанные между собой операции и вы не хотите “засорять” классы такими операциями.

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

  • Group.php
                  
    <?php
    
    namespace DesignPatterns\Behavioral\Visitor;
    
    /**
     * Class Group
     * @package DesignPatterns\Behavioral\Visitor
     */
    class Group implements Role
    {
        /**
         * @var string
         */
        private $name;
    
        /**
         * Group constructor.
         *
         * @param string $name
         */
        public function __construct(string $name)
        {
            $this->name = $name;
        }
    
        /**
         * @return string
         */
        public function getName(): string
        {
            return sprintf('Group: %s', $this->name);
        }
    
        /**
         * @param RoleVisitorInterface $visitor
         *
         * @return void
         */
        public function accept(RoleVisitorInterface $visitor)
        {
            $visitor->visitGroup($this);
        }
    }
    
                  
  • Role.php
                  
    <?php
    
    namespace DesignPatterns\Behavioral\Visitor;
    
    /**
     * Interface Role
     * @package DesignPatterns\Behavioral\Visitor
     */
    interface Role
    {
        /**
         * @param RoleVisitorInterface $visitor
         *
         * @return void
         */
        public function accept(RoleVisitorInterface $visitor);
    }
    
                  
  • RoleVisitor.php
                  
    <?php
    
    namespace DesignPatterns\Behavioral\Visitor;
    
    /**
     * Class RoleVisitor
     * @package DesignPatterns\Behavioral\Visitor
     */
    class RoleVisitor implements RoleVisitorInterface
    {
        /**
         * @var Role[]
         */
        private $visited = [];
    
        /**
         * @param Group $role
         */
        public function visitGroup(Group $role)
        {
            $this->visited[] = $role;
        }
    
        /**
         * @param User $role
         *
         * @return void
         */
        public function visitUser(User $role)
        {
            $this->visited[] = $role;
        }
    
        /**
         * @return Role[]
         */
        public function getVisited(): array
        {
            return $this->visited;
        }
    }
    
                  
  • RoleVisitorInterface.php
                  
    <?php
    
    namespace DesignPatterns\Behavioral\Visitor;
    
    /**
     * Interface RoleVisitorInterface
     * @package DesignPatterns\Behavioral\Visitor
     */
    interface RoleVisitorInterface
    {
        /**
         * @param User $role
         *
         * @return void
         */
        public function visitUser(User $role);
    
        /**
         * @param Group $role
         *
         * @return void
         */
        public function visitGroup(Group $role);
    }
    
                  
  • User.php
                  
    <?php
    
    namespace DesignPatterns\Behavioral\Visitor;
    
    /**
     * Class User
     * @package DesignPatterns\Behavioral\Visitor
     */
    class User implements Role
    {
        /**
         * @var string
         */
        private $name;
    
        /**
         * User constructor.
         *
         * @param string $name
         */
        public function __construct(string $name)
        {
            $this->name = $name;
        }
    
        /**
         * @return string
         */
        public function getName(): string
        {
            return sprintf('User %s', $this->name);
        }
    
        /**
         * @param RoleVisitorInterface $visitor
         *
         * @return void
         */
        public function accept(RoleVisitorInterface $visitor)
        {
            $visitor->visitUser($this);
        }
    }
    
                  
  • Test case:

    VisitorTest.php
      
    <?php
    
    namespace DesignPatterns\Tests\Behavioral\Visitor;
    
    use DesignPatterns\Behavioral\Visitor\Group;
    use DesignPatterns\Behavioral\Visitor\Role;
    use DesignPatterns\Behavioral\Visitor\RoleVisitor;
    use DesignPatterns\Behavioral\Visitor\User;
    use PHPUnit_Framework_TestCase;
    
    class VisitorTest extends PHPUnit_Framework_TestCase
    {
        /**
         * @var RoleVisitor
         */
        private $visitor;
    
        protected function setUp(): void
        {
            $this->visitor = new RoleVisitor();
        }
    
        public function provideRoles()
        {
            return [
                [new User('Dominik')],
                [new Group('Administrators')],
            ];
        }
    
        /**
         * @dataProvider provideRoles
         *
         * @param Role $role
         */
        public function testVisitSomeRole(Role $role)
        {
            $role->accept($this->visitor);
            $this->assertSame($role, $this->visitor->getVisited()[0]);
        }
    }