cs Visitor

This commit is contained in:
Dominik Liebler
2013-09-12 11:20:10 +02:00
parent af442a9980
commit 032cc57cf6
6 changed files with 20 additions and 28 deletions

View File

@@ -39,7 +39,7 @@ class VisitorTest extends \PHPUnit_Framework_TestCase
} }
/** /**
* @expectedException InvalidArgumentException * @expectedException \InvalidArgumentException
* @expectedExceptionMessage Mock * @expectedExceptionMessage Mock
*/ */
public function testUnknownObject() public function testUnknownObject()

View File

@@ -3,11 +3,10 @@
namespace DesignPatterns\Visitor; namespace DesignPatterns\Visitor;
/** /**
* An example of a Visitee : Group * An example of a Visitor: Group
*/ */
class Group extends Role class Group extends Role
{ {
/** /**
* @var string * @var string
*/ */
@@ -28,5 +27,4 @@ class Group extends Role
{ {
return "Group: " . $this->name; return "Group: " . $this->name;
} }
} }

View File

@@ -7,34 +7,34 @@ namespace DesignPatterns\Visitor;
* *
* Purpose: * Purpose:
* The Visitor Pattern lets you outsource operations on objects to other objects. The main reason to do this is to keep * The Visitor Pattern lets you outsource operations on objects to other objects. The main reason to do this is to keep
* a seperation of concerns. But classes have to define an contract to allow visitors (the "accept" method in the example below). * a separation of concerns. But classes have to define an contract to allow visitors (the "accept" method in the example below).
* *
* The contract is an abstract class but you can have also a clean interface. * The contract is an abstract class but you can have also a clean interface.
* In that case, each Visitee has to choose itself which method to invoke on the visitor. * In that case, each Visitor has to choose itself which method to invoke on the visitor.
*/ */
abstract class Role abstract class Role
{ {
/** /**
* This method handles a double dispatch based on the shortname of the Visitee * 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 * Feel free to override it if your object must call another visiting behavior
* *
* @param \DesignPatterns\Visitor\RoleVisitor $visitor * @param \DesignPatterns\Visitor\RoleVisitorInterface $visitor
*
* @throws \InvalidArgumentException
*/ */
public function accept(RoleVisitor $visitor) public function accept(RoleVisitorInterface $visitor)
{ {
// this trick to simulate double-dispatch based on type-hinting // this trick to simulate double-dispatch based on type-hinting
$fqcn = get_called_class(); $klass = get_called_class();
preg_match('#([^\\\\]+)$#', $fqcn, $extract); preg_match('#([^\\\\]+)$#', $klass, $extract);
$visitingMethod = 'visit' . $extract[1]; $visitingMethod = 'visit' . $extract[1];
// this ensures strong typing with visitor interface, not some visitor objects // this ensures strong typing with visitor interface, not some visitor objects
if (!method_exists(__NAMESPACE__ . '\RoleVisitor', $visitingMethod)) { if (!method_exists(__NAMESPACE__ . '\RoleVisitorInterface', $visitingMethod)) {
throw new \InvalidArgumentException("The visitor you provide cannot visit a $fqcn instance"); throw new \InvalidArgumentException("The visitor you provide cannot visit a $klass instance");
} }
call_user_func(array($visitor, $visitingMethod), $this); call_user_func(array($visitor, $visitingMethod), $this);
} }
} }

View File

@@ -7,11 +7,10 @@ namespace DesignPatterns\Visitor;
* *
* An implementation of a concrete Visitor * An implementation of a concrete Visitor
*/ */
class RolePrintVisitor implements RoleVisitor class RolePrintVisitor implements RoleVisitorInterface
{ {
/** /**
* @inheritdoc * {@inheritdoc}
*/ */
public function visitGroup(Group $role) public function visitGroup(Group $role)
{ {
@@ -19,11 +18,10 @@ class RolePrintVisitor implements RoleVisitor
} }
/** /**
* @inheritdoc * {@inheritdoc}
*/ */
public function visitUser(User $role) public function visitUser(User $role)
{ {
echo "Role: " . $role->getName(); echo "Role: " . $role->getName();
} }
} }

View File

@@ -13,9 +13,8 @@ namespace DesignPatterns\Visitor;
* Note 2 : the visitor must not choose itself which method to * Note 2 : the visitor must not choose itself which method to
* invoke, it is the Visitee that make this decision. * invoke, it is the Visitee that make this decision.
*/ */
interface RoleVisitor interface RoleVisitorInterface
{ {
/** /**
* Visit a User object * Visit a User object
* *
@@ -24,7 +23,7 @@ interface RoleVisitor
public function visitUser(User $role); public function visitUser(User $role);
/** /**
* Visit a Group objet * Visit a Group object
* *
* @param \DesignPatterns\Visitor\Group $role * @param \DesignPatterns\Visitor\Group $role
*/ */

View File

@@ -9,7 +9,6 @@ namespace DesignPatterns\Visitor;
*/ */
class User extends Role class User extends Role
{ {
/** /**
* @var string * @var string
*/ */
@@ -30,6 +29,4 @@ class User extends Role
{ {
return "User " . $this->name; return "User " . $this->name;
} }
} }