Посетитель (англ. 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]);
}
}