start a restructure

This commit is contained in:
Antonio Spinelli
2014-03-21 18:03:44 -03:00
parent b0b0d4a1a4
commit e59d70a0ac
180 changed files with 21 additions and 16 deletions

View File

@@ -0,0 +1,30 @@
<?php
namespace DesignPatterns\Visitor;
/**
* An example of a Visitor: Group
*/
class Group extends Role
{
/**
* @var string
*/
protected $name;
/**
* @param string $name
*/
public function __construct($name)
{
$this->name = (string) $name;
}
/**
* @return string
*/
public function getName()
{
return "Group: " . $this->name;
}
}

View File

@@ -0,0 +1,8 @@
# Visitor
## Purpose
The Visitor Pattern lets you outsource operations on objects to other objects. The main reason to do this is to keep a separation of concerns.
But classes have to define a contract to allow visitors (the `Role::accept` method in the example).
The contract is an abstract class but you can have also a clean interface. In that case, each Visitor has to choose itself which method to invoke on the visitor.

View File

@@ -0,0 +1,33 @@
<?php
namespace DesignPatterns\Visitor;
/**
* class Role
*/
abstract class 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\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);
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace DesignPatterns\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();
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace DesignPatterns\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.
*/
interface RoleVisitorInterface
{
/**
* Visit a User object
*
* @param \DesignPatterns\Visitor\User $role
*/
public function visitUser(User $role);
/**
* Visit a Group object
*
* @param \DesignPatterns\Visitor\Group $role
*/
public function visitGroup(Group $role);
}

View File

@@ -0,0 +1,47 @@
<?php
namespace DesignPatterns\Tests\Visitor;
use DesignPatterns\Visitor;
/**
* VisitorTest tests the visitor pattern
*/
class VisitorTest extends \PHPUnit_Framework_TestCase
{
protected $visitor;
protected function setUp()
{
$this->visitor = new Visitor\RolePrintVisitor();
}
public function getRole()
{
return array(
array(new Visitor\User("Dominik"), 'Role: User Dominik'),
array(new Visitor\Group("Administrators"), 'Role: Group: Administrators')
);
}
/**
* @dataProvider getRole
*/
public function testVisitSomeRole(Visitor\Role $role, $expect)
{
$this->expectOutputString($expect);
$role->accept($this->visitor);
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Mock
*/
public function testUnknownObject()
{
$mock = $this->getMockForAbstractClass('DesignPatterns\Visitor\Role');
$mock->accept($this->visitor);
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace DesignPatterns\Visitor;
/**
* Visitor Pattern
*
* One example for a visitee. Each visitee has to extends Role
*/
class User extends Role
{
/**
* @var string
*/
protected $name;
/**
* @param string $name
*/
public function __construct($name)
{
$this->name = (string) $name;
}
/**
* @return string
*/
public function getName()
{
return "User " . $this->name;
}
}