访问者模式 目的 访问者模式 允许你将对象的操作外包给其他对象,这样做的主要原因是为了保持关注点的分离。但是,类必须定义一个允许访问者访问的契约(比如,下面例子中的 Role::accept() 方法)。
这个契约是一个抽象类,但也可以是一个接口。在那种情况下,每个访问者必须选择对访问者调用哪个方法。
UML 类图
代码 RoleVisitor.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php declare (strict_types = 1 );namespace DesignPatterns \Behavioral \Visitor ;interface RoleVisitor { public function visitUser (User $role ) ; public function visitGroup (Group $role ) ; }
RecordingVisitor.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <?php declare (strict_types = 1 );namespace DesignPatterns \Behavioral \Visitor ;class RecordingVisitor implements RoleVisitor { private array $visited = []; public function visitGroup (Group $role ) { $this ->visited[] = $role ; } public function visitUser (User $role ) { $this ->visited[] = $role ; } public function getVisited ( ): array { return $this ->visited; } }
Role.php 1 2 3 4 5 6 7 8 <?php declare (strict_types = 1 );namespace DesignPatterns \Behavioral \Visitor ;interface Role { public function accept (RoleVisitor $visitor ) ; }
User.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?php declare (strict_types = 1 );namespace DesignPatterns \Behavioral \Visitor ;class User implements Role { private string $name ; public function __construct (string $name ) { $this ->name = $name ; } public function getName ( ): string { return sprintf ('User %s' , $this ->name); } public function accept (RoleVisitor $visitor ) { $visitor ->visitUser ($this ); } }
Group.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?php declare (strict_types = 1 );namespace DesignPatterns \Behavioral \Visitor ;class Group implements Role { private string $name ; public function __construct (string $name ) { $this ->name = $name ; } public function getName ( ): string { return sprintf ('Group: %s' , $this ->name); } public function accept (RoleVisitor $visitor ) { $visitor ->visitGroup ($this ); } }
测试 Tests/VisitorTest.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <?php declare (strict_types = 1 );namespace DesignPatterns \Tests \Visitor \Tests ;use DesignPatterns \Behavioral \Visitor \RecordingVisitor ;use DesignPatterns \Behavioral \Visitor \User ;use DesignPatterns \Behavioral \Visitor \Group ;use DesignPatterns \Behavioral \Visitor \Role ;use DesignPatterns \Behavioral \Visitor ;use PHPUnit \Framework \TestCase ;class VisitorTest extends TestCase { private RecordingVisitor $visitor ; protected function setUp ( ): void { $this ->visitor = new RecordingVisitor (); } public function provideRoles ( ) { return [ [new User ('Dominik' )], [new Group ('Administrators' )], ]; } public function testVisitSomeRole (Role $role ) { $role ->accept ($this ->visitor); $this ->assertSame ($role , $this ->visitor->getVisited ()[0 ]); } }