diff --git a/Behavioral/README.md b/Behavioral/README.md deleted file mode 100644 index b98202b..0000000 --- a/Behavioral/README.md +++ /dev/null @@ -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) diff --git a/Behavioral/Visitor/Group.php b/Behavioral/Visitor/Group.php index b2c9d90..e4a9a65 100644 --- a/Behavioral/Visitor/Group.php +++ b/Behavioral/Visitor/Group.php @@ -2,29 +2,25 @@ namespace DesignPatterns\Behavioral\Visitor; -/** - * An example of a Visitor: Group. - */ -class Group extends Role +class Group implements Role { /** * @var string */ - protected $name; + private $name; - /** - * @param string $name - */ - public function __construct($name) + public function __construct(string $name) { - $this->name = (string) $name; + $this->name = $name; } - /** - * @return string - */ - public function getName() + public function getName(): string { - return 'Group: '.$this->name; + return sprintf('Group: %s', $this->name); + } + + public function accept(RoleVisitorInterface $visitor) + { + $visitor->visitGroup($this); } } diff --git a/Behavioral/Visitor/README.rst b/Behavioral/Visitor/README.rst index ba256b9..7484356 100644 --- a/Behavioral/Visitor/README.rst +++ b/Behavioral/Visitor/README.rst @@ -31,9 +31,9 @@ RoleVisitorInterface.php :language: php :linenos: -RolePrintVisitor.php +RoleVisitor.php -.. literalinclude:: RolePrintVisitor.php +.. literalinclude:: RoleVisitor.php :language: php :linenos: diff --git a/Behavioral/Visitor/Role.php b/Behavioral/Visitor/Role.php index 011a0fb..1a55c74 100644 --- a/Behavioral/Visitor/Role.php +++ b/Behavioral/Visitor/Role.php @@ -2,32 +2,7 @@ namespace DesignPatterns\Behavioral\Visitor; -/** - * class Role. - */ -abstract class Role +interface Role { - /** - * 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); - } + public function accept(RoleVisitorInterface $visitor); } diff --git a/Behavioral/Visitor/RolePrintVisitor.php b/Behavioral/Visitor/RolePrintVisitor.php deleted file mode 100644 index 49777cf..0000000 --- a/Behavioral/Visitor/RolePrintVisitor.php +++ /dev/null @@ -1,27 +0,0 @@ -getName(); - } - - /** - * {@inheritdoc} - */ - public function visitUser(User $role) - { - echo 'Role: '.$role->getName(); - } -} diff --git a/Behavioral/Visitor/RoleVisitor.php b/Behavioral/Visitor/RoleVisitor.php new file mode 100644 index 0000000..fc368b2 --- /dev/null +++ b/Behavioral/Visitor/RoleVisitor.php @@ -0,0 +1,29 @@ +visited[] = $role; + } + + public function visitUser(User $role) + { + $this->visited[] = $role; + } + + /** + * @return Role[] + */ + public function getVisited(): array + { + return $this->visited; + } +} diff --git a/Behavioral/Visitor/RoleVisitorInterface.php b/Behavioral/Visitor/RoleVisitorInterface.php index e8ba0ec..b2aff5e 100644 --- a/Behavioral/Visitor/RoleVisitorInterface.php +++ b/Behavioral/Visitor/RoleVisitorInterface.php @@ -3,29 +3,12 @@ namespace DesignPatterns\Behavioral\Visitor; /** - * Visitor Pattern. - * - * 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. + * Note: the visitor must not choose itself which method to + * invoke, it is the Visitee that make this decision */ interface RoleVisitorInterface { - /** - * Visit a User object. - * - * @param \DesignPatterns\Behavioral\Visitor\User $role - */ public function visitUser(User $role); - /** - * Visit a Group object. - * - * @param \DesignPatterns\Behavioral\Visitor\Group $role - */ public function visitGroup(Group $role); } diff --git a/Behavioral/Visitor/Tests/VisitorTest.php b/Behavioral/Visitor/Tests/VisitorTest.php index f3b5bc7..ce6480b 100644 --- a/Behavioral/Visitor/Tests/VisitorTest.php +++ b/Behavioral/Visitor/Tests/VisitorTest.php @@ -4,42 +4,34 @@ namespace DesignPatterns\Tests\Visitor\Tests; use DesignPatterns\Behavioral\Visitor; -/** - * VisitorTest tests the visitor pattern. - */ class VisitorTest extends \PHPUnit_Framework_TestCase { - protected $visitor; + /** + * @var Visitor\RoleVisitor + */ + private $visitor; protected function setUp() { - $this->visitor = new Visitor\RolePrintVisitor(); + $this->visitor = new Visitor\RoleVisitor(); } - public function getRole() + public function provideRoles() { - return array( - array(new Visitor\User('Dominik'), 'Role: User Dominik'), - array(new Visitor\Group('Administrators'), 'Role: Group: Administrators'), - ); + return [ + [new Visitor\User('Dominik')], + [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); - } - - /** - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Mock - */ - public function testUnknownObject() - { - $mock = $this->getMockForAbstractClass('DesignPatterns\Behavioral\Visitor\Role'); - $mock->accept($this->visitor); + $this->assertSame($role, $this->visitor->getVisited()[0]); } } diff --git a/Behavioral/Visitor/User.php b/Behavioral/Visitor/User.php index 5a95fbe..f3d9ad3 100644 --- a/Behavioral/Visitor/User.php +++ b/Behavioral/Visitor/User.php @@ -2,31 +2,25 @@ namespace DesignPatterns\Behavioral\Visitor; -/** - * Visitor Pattern. - * - * One example for a visitee. Each visitee has to extends Role - */ -class User extends Role +class User implements Role { /** * @var string */ - protected $name; + private $name; - /** - * @param string $name - */ - public function __construct($name) + public function __construct(string $name) { - $this->name = (string) $name; + $this->name = $name; } - /** - * @return string - */ - public function getName() + public function getName(): string { - return 'User '.$this->name; + return sprintf('User %s', $this->name); + } + + public function accept(RoleVisitorInterface $visitor) + { + $visitor->visitUser($this); } }