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