mirror of
https://github.com/DesignPatternsPHP/DesignPatternsPHP.git
synced 2025-07-18 13:51:14 +02:00
PHP7 Visitor
This commit is contained in:
@@ -1,19 +0,0 @@
|
|||||||
# Behavioral
|
|
||||||
|
|
||||||
In software engineering, behavioral design patterns are design patterns that
|
|
||||||
identify common communication patterns between objects and realize these
|
|
||||||
patterns. By doing so, these patterns increase flexibility in carrying out this
|
|
||||||
communication.
|
|
||||||
|
|
||||||
* [ChainOfResponsibilities](ChainOfResponsibilities) [:notebook:](http://en.wikipedia.org/wiki/Chain_of_responsibility_pattern)
|
|
||||||
* [Command](Command) [:notebook:](http://en.wikipedia.org/wiki/Command_pattern)
|
|
||||||
* [Iterator](Iterator) [:notebook:](http://en.wikipedia.org/wiki/Iterator_pattern)
|
|
||||||
* [Mediator](Mediator) [:notebook:](http://en.wikipedia.org/wiki/Mediator_pattern)
|
|
||||||
* [Memento](Memento) [:notebook:](http://en.wikipedia.org/wiki/Memento_pattern)
|
|
||||||
* [NullObject](NullObject) [:notebook:](http://en.wikipedia.org/wiki/Null_Object_pattern)
|
|
||||||
* [Observer](Observer) [:notebook:](http://en.wikipedia.org/wiki/Observer_pattern)
|
|
||||||
* [Specification](Specification) [:notebook:](http://en.wikipedia.org/wiki/Specification_pattern)
|
|
||||||
* [State](State) [:notebook:](http://en.wikipedia.org/wiki/State_pattern)
|
|
||||||
* [Strategy](Strategy) [:notebook:](http://en.wikipedia.org/wiki/Strategy_pattern)
|
|
||||||
* [TemplateMethod](TemplateMethod) [:notebook:](http://en.wikipedia.org/wiki/Template_method_pattern)
|
|
||||||
* [Visitor](Visitor) [:notebook:](http://en.wikipedia.org/wiki/Visitor_pattern)
|
|
@@ -2,29 +2,25 @@
|
|||||||
|
|
||||||
namespace DesignPatterns\Behavioral\Visitor;
|
namespace DesignPatterns\Behavioral\Visitor;
|
||||||
|
|
||||||
/**
|
class Group implements Role
|
||||||
* An example of a Visitor: Group.
|
|
||||||
*/
|
|
||||||
class Group extends Role
|
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $name;
|
private $name;
|
||||||
|
|
||||||
/**
|
public function __construct(string $name)
|
||||||
* @param string $name
|
|
||||||
*/
|
|
||||||
public function __construct($name)
|
|
||||||
{
|
{
|
||||||
$this->name = (string) $name;
|
$this->name = $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function getName(): string
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getName()
|
|
||||||
{
|
{
|
||||||
return 'Group: '.$this->name;
|
return sprintf('Group: %s', $this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function accept(RoleVisitorInterface $visitor)
|
||||||
|
{
|
||||||
|
$visitor->visitGroup($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,9 +31,9 @@ RoleVisitorInterface.php
|
|||||||
:language: php
|
:language: php
|
||||||
:linenos:
|
:linenos:
|
||||||
|
|
||||||
RolePrintVisitor.php
|
RoleVisitor.php
|
||||||
|
|
||||||
.. literalinclude:: RolePrintVisitor.php
|
.. literalinclude:: RoleVisitor.php
|
||||||
:language: php
|
:language: php
|
||||||
:linenos:
|
:linenos:
|
||||||
|
|
||||||
|
@@ -2,32 +2,7 @@
|
|||||||
|
|
||||||
namespace DesignPatterns\Behavioral\Visitor;
|
namespace DesignPatterns\Behavioral\Visitor;
|
||||||
|
|
||||||
/**
|
interface Role
|
||||||
* class Role.
|
|
||||||
*/
|
|
||||||
abstract class Role
|
|
||||||
{
|
{
|
||||||
/**
|
public function accept(RoleVisitorInterface $visitor);
|
||||||
* This method handles a double dispatch based on the short name of the Visitor.
|
|
||||||
*
|
|
||||||
* Feel free to override it if your object must call another visiting behavior
|
|
||||||
*
|
|
||||||
* @param \DesignPatterns\Behavioral\Visitor\RoleVisitorInterface $visitor
|
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException
|
|
||||||
*/
|
|
||||||
public function accept(RoleVisitorInterface $visitor)
|
|
||||||
{
|
|
||||||
// this trick to simulate double-dispatch based on type-hinting
|
|
||||||
$klass = get_called_class();
|
|
||||||
preg_match('#([^\\\\]+)$#', $klass, $extract);
|
|
||||||
$visitingMethod = 'visit'.$extract[1];
|
|
||||||
|
|
||||||
// this ensures strong typing with visitor interface, not some visitor objects
|
|
||||||
if (!method_exists(__NAMESPACE__.'\RoleVisitorInterface', $visitingMethod)) {
|
|
||||||
throw new \InvalidArgumentException("The visitor you provide cannot visit a $klass instance");
|
|
||||||
}
|
|
||||||
|
|
||||||
call_user_func(array($visitor, $visitingMethod), $this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1,27 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DesignPatterns\Behavioral\Visitor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Visitor Pattern.
|
|
||||||
*
|
|
||||||
* An implementation of a concrete Visitor
|
|
||||||
*/
|
|
||||||
class RolePrintVisitor implements RoleVisitorInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function visitGroup(Group $role)
|
|
||||||
{
|
|
||||||
echo 'Role: '.$role->getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function visitUser(User $role)
|
|
||||||
{
|
|
||||||
echo 'Role: '.$role->getName();
|
|
||||||
}
|
|
||||||
}
|
|
29
Behavioral/Visitor/RoleVisitor.php
Normal file
29
Behavioral/Visitor/RoleVisitor.php
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
}
|
@@ -3,29 +3,12 @@
|
|||||||
namespace DesignPatterns\Behavioral\Visitor;
|
namespace DesignPatterns\Behavioral\Visitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visitor Pattern.
|
* Note: the visitor must not choose itself which method to
|
||||||
*
|
* invoke, it is the Visitee that make this decision
|
||||||
* The contract for the visitor.
|
|
||||||
*
|
|
||||||
* Note 1 : in C++ or Java, with method polymorphism based on type-hint, there are many
|
|
||||||
* methods visit() with different type for the 'role' parameter.
|
|
||||||
*
|
|
||||||
* Note 2 : the visitor must not choose itself which method to
|
|
||||||
* invoke, it is the Visitee that make this decision.
|
|
||||||
*/
|
*/
|
||||||
interface RoleVisitorInterface
|
interface RoleVisitorInterface
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Visit a User object.
|
|
||||||
*
|
|
||||||
* @param \DesignPatterns\Behavioral\Visitor\User $role
|
|
||||||
*/
|
|
||||||
public function visitUser(User $role);
|
public function visitUser(User $role);
|
||||||
|
|
||||||
/**
|
|
||||||
* Visit a Group object.
|
|
||||||
*
|
|
||||||
* @param \DesignPatterns\Behavioral\Visitor\Group $role
|
|
||||||
*/
|
|
||||||
public function visitGroup(Group $role);
|
public function visitGroup(Group $role);
|
||||||
}
|
}
|
||||||
|
@@ -4,42 +4,34 @@ namespace DesignPatterns\Tests\Visitor\Tests;
|
|||||||
|
|
||||||
use DesignPatterns\Behavioral\Visitor;
|
use DesignPatterns\Behavioral\Visitor;
|
||||||
|
|
||||||
/**
|
|
||||||
* VisitorTest tests the visitor pattern.
|
|
||||||
*/
|
|
||||||
class VisitorTest extends \PHPUnit_Framework_TestCase
|
class VisitorTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
protected $visitor;
|
/**
|
||||||
|
* @var Visitor\RoleVisitor
|
||||||
|
*/
|
||||||
|
private $visitor;
|
||||||
|
|
||||||
protected function setUp()
|
protected function setUp()
|
||||||
{
|
{
|
||||||
$this->visitor = new Visitor\RolePrintVisitor();
|
$this->visitor = new Visitor\RoleVisitor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRole()
|
public function provideRoles()
|
||||||
{
|
{
|
||||||
return array(
|
return [
|
||||||
array(new Visitor\User('Dominik'), 'Role: User Dominik'),
|
[new Visitor\User('Dominik')],
|
||||||
array(new Visitor\Group('Administrators'), 'Role: Group: Administrators'),
|
[new Visitor\Group('Administrators')],
|
||||||
);
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider getRole
|
* @dataProvider provideRoles
|
||||||
|
*
|
||||||
|
* @param Visitor\Role $role
|
||||||
*/
|
*/
|
||||||
public function testVisitSomeRole(Visitor\Role $role, $expect)
|
public function testVisitSomeRole(Visitor\Role $role)
|
||||||
{
|
{
|
||||||
$this->expectOutputString($expect);
|
|
||||||
$role->accept($this->visitor);
|
$role->accept($this->visitor);
|
||||||
}
|
$this->assertSame($role, $this->visitor->getVisited()[0]);
|
||||||
|
|
||||||
/**
|
|
||||||
* @expectedException \InvalidArgumentException
|
|
||||||
* @expectedExceptionMessage Mock
|
|
||||||
*/
|
|
||||||
public function testUnknownObject()
|
|
||||||
{
|
|
||||||
$mock = $this->getMockForAbstractClass('DesignPatterns\Behavioral\Visitor\Role');
|
|
||||||
$mock->accept($this->visitor);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,31 +2,25 @@
|
|||||||
|
|
||||||
namespace DesignPatterns\Behavioral\Visitor;
|
namespace DesignPatterns\Behavioral\Visitor;
|
||||||
|
|
||||||
/**
|
class User implements Role
|
||||||
* Visitor Pattern.
|
|
||||||
*
|
|
||||||
* One example for a visitee. Each visitee has to extends Role
|
|
||||||
*/
|
|
||||||
class User extends Role
|
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $name;
|
private $name;
|
||||||
|
|
||||||
/**
|
public function __construct(string $name)
|
||||||
* @param string $name
|
|
||||||
*/
|
|
||||||
public function __construct($name)
|
|
||||||
{
|
{
|
||||||
$this->name = (string) $name;
|
$this->name = $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function getName(): string
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getName()
|
|
||||||
{
|
{
|
||||||
return 'User '.$this->name;
|
return sprintf('User %s', $this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function accept(RoleVisitorInterface $visitor)
|
||||||
|
{
|
||||||
|
$visitor->visitUser($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user