objectif
Le modèle de visiteur vous permet d'externaliser les opérations sur les objets vers d'autres objets.
La raison principale en est la séparation des préoccupations (structure et manipulation des données). Mais la classe visitée doit conclure un contrat pour accepter le visiteur. (Voir la méthode Role :: accept dans l'exemple pour plus de détails)
Le contrat peut être une classe abstraite ou une interface. Dans ce cas, chaque visiteur doit choisir la méthode du visiteur à appeler.
Graphiques UML
Code
- RoleVisitorInterface.php
<?php
namespace DesignPatterns\Behavioral\Visitor;
/**
* 注意:访问者不能自行选择调用哪个方法,
* 它是由 Visitee 决定的。
*/
interface RoleVisitorInterface
{
public function visitUser(User $role);
public function visitGroup(Group $role);
}
- RoleVisitor.php
<?php
namespace DesignPatterns\Behavioral\Visitor;
class RoleVisitor implements RoleVisitorInterface
{
/**
* @var Role[]
*/
private $visited = [];
public function visitGroup(Group $role)
{
$this->visited[] = $role;
}
public function visitUser(User $role)
{
$this->visited[] = $role;
}
/**
* @return Role[]
*/
public function getVisited(): array
{
return $this->visited;
}
}
- Role.php
<?php
namespace DesignPatterns\Behavioral\Visitor;
interface Role
{
public function accept(RoleVisitorInterface $visitor);
}
- User.php
<?php
namespace DesignPatterns\Behavioral\Visitor;
class User implements Role
{
/**
* @var string
*/
private $name;
public function __construct(string $name)
{
$this->name = $name;
}
public function getName(): string
{
return sprintf('User %s', $this->name);
}
public function accept(RoleVisitorInterface $visitor)
{
$visitor->visitUser($this);
}
}
- Group.php
<?php
namespace DesignPatterns\Behavioral\Visitor;
class Group implements Role
{
/**
* @var string
*/
private $name;
public function __construct(string $name)
{
$this->name = $name;
}
public function getName(): string
{
return sprintf('Group: %s', $this->name);
}
public function accept(RoleVisitorInterface $visitor)
{
$visitor->visitGroup($this);
}
}
tester
- Tests / VisitorTest.php
<?php
namespace DesignPatterns\Tests\Visitor\Tests;
use DesignPatterns\Behavioral\Visitor;
use PHPUnit\Framework\TestCase;
class VisitorTest extends TestCase
{
/**
* @var Visitor\RoleVisitor
*/
private $visitor;
protected function setUp()
{
$this->visitor = new Visitor\RoleVisitor();
}
public function provideRoles()
{
return [
[new Visitor\User('Dominik')],
[new Visitor\Group('Administrators')],
];
}
/**
* @dataProvider provideRoles
*
* @param Visitor\Role $role
*/
public function testVisitSomeRole(Visitor\Role $role)
{
$role->accept($this->visitor);
$this->assertSame($role, $this->visitor->getVisited()[0]);
}
}
Le chemin de croissance de PHP Internet Architect * Le guide ultime des «modèles de conception»
Entretien avec 10 entreprises, obtenez 9 offres, questions d'entretien PHP en 2020
★ Si vous aimez mon article et que vous souhaitez communiquer et apprendre avec des développeurs plus expérimentés, obtenir plus de conseils techniques et des conseils liés aux entretiens avec de grandes entreprises, bienvenue à rejoindre notre groupe, mot de passe: phpzh
Le dernier tutoriel avancé PHP en 2020, série complète!
Si le contenu est bon, j'espère que tout le monde vous soutiendra et vous encouragera à donner un `` like / like '' et à communiquer ensemble; de plus, si vous avez des questions, vous pouvez suggérer ce que vous voulez voir dans les commentaires.