目的
访问者模式可以让你将对象操作外包给其他对象。
这样做的最主要原因就是关注(数据结构和数据操作)分离。但是被访问的类必须定一个契约接受访问者。 (详见例子中 Role::accept 方法)
契约可以是一个抽象类也可以就是一个接口。在此情况下,每个访问者必须自行选择调用访问者的哪个方法。
UML图
代码
- 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);
}
}
测试
- 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]);
}
}
PHP 互联网架构师 50K 成长指南+行业问题解决总纲(持续更新)
面试10家公司,收获9个offer,2020年PHP 面试问题
★如果喜欢我的文章,想与更多资深开发者一起交流学习的话,获取更多大厂面试相关技术咨询和指导,欢迎加入我们的群啊,暗号:phpzh
内容不错的话希望大家支持鼓励下点个赞/喜欢,欢迎一起来交流;另外如果有什么问题 建议 想看的内容可以在评论提出
来源:oschina
链接:https://my.oschina.net/u/4399511/blog/4637434