PHP7 Observer

This commit is contained in:
Dominik Liebler 2016-09-22 10:54:22 +02:00
parent b707bf064e
commit 9b9eee5a4c
6 changed files with 707 additions and 444 deletions

View File

@ -5,65 +5,16 @@ namespace DesignPatterns\Behavioral\Observer\Tests;
use DesignPatterns\Behavioral\Observer\User; use DesignPatterns\Behavioral\Observer\User;
use DesignPatterns\Behavioral\Observer\UserObserver; use DesignPatterns\Behavioral\Observer\UserObserver;
/**
* ObserverTest tests the Observer pattern.
*/
class ObserverTest extends \PHPUnit_Framework_TestCase class ObserverTest extends \PHPUnit_Framework_TestCase
{ {
protected $observer; public function testChangeInUserLeadsToUserObserverBeingNotified()
protected function setUp()
{ {
$this->observer = new UserObserver(); $observer = new UserObserver();
}
/** $user = new User();
* Tests the notification. $user->attach($observer);
*/
public function testNotify()
{
$this->expectOutputString('DesignPatterns\Behavioral\Observer\User has been updated');
$subject = new User();
$subject->attach($this->observer); $user->changeEmail('foo@bar.com');
$subject->property = 123; $this->assertCount(1, $observer->getChangedUsers());
}
/**
* Tests the subscribing.
*/
public function testAttachDetach()
{
$subject = new User();
$reflection = new \ReflectionProperty($subject, 'observers');
$reflection->setAccessible(true);
/** @var \SplObjectStorage $observers */
$observers = $reflection->getValue($subject);
$this->assertInstanceOf('SplObjectStorage', $observers);
$this->assertFalse($observers->contains($this->observer));
$subject->attach($this->observer);
$this->assertTrue($observers->contains($this->observer));
$subject->detach($this->observer);
$this->assertFalse($observers->contains($this->observer));
}
/**
* Tests the update() invocation on a mockup.
*/
public function testUpdateCalling()
{
$subject = new User();
$observer = $this->createMock('SplObserver');
$subject->attach($observer);
$observer->expects($this->once())
->method('update')
->with($subject);
$subject->notify();
} }
} }

View File

@ -3,60 +3,42 @@
namespace DesignPatterns\Behavioral\Observer; namespace DesignPatterns\Behavioral\Observer;
/** /**
* Observer pattern : The observed object (the subject). * User implements the observed object (called Subject), it maintains a list of observers and sends notifications to
* * them in case changes are made on the User object
* The subject maintains a list of Observers and sends notifications.
*/ */
class User implements \SplSubject class User implements \SplSubject
{ {
/** /**
* user data. * @var string
*
* @var array
*/ */
protected $data = array(); private $email;
/** /**
* observers.
*
* @var \SplObjectStorage * @var \SplObjectStorage
*/ */
protected $observers; private $observers;
public function __construct() public function __construct()
{ {
$this->observers = new \SplObjectStorage(); $this->observers = new \SplObjectStorage();
} }
/**
* attach a new observer.
*
* @param \SplObserver $observer
*
* @return void
*/
public function attach(\SplObserver $observer) public function attach(\SplObserver $observer)
{ {
$this->observers->attach($observer); $this->observers->attach($observer);
} }
/**
* detach an observer.
*
* @param \SplObserver $observer
*
* @return void
*/
public function detach(\SplObserver $observer) public function detach(\SplObserver $observer)
{ {
$this->observers->detach($observer); $this->observers->detach($observer);
} }
/** public function changeEmail(string $email)
* notify observers. {
* $this->email = $email;
* @return void $this->notify();
*/ }
public function notify() public function notify()
{ {
/** @var \SplObserver $observer */ /** @var \SplObserver $observer */
@ -64,21 +46,4 @@ class User implements \SplSubject
$observer->update($this); $observer->update($this);
} }
} }
/**
* Ideally one would better write setter/getter for all valid attributes and only call notify()
* on attributes that matter when changed.
*
* @param string $name
* @param mixed $value
*
* @return void
*/
public function __set($name, $value)
{
$this->data[$name] = $value;
// notify the observers, that user has been updated
$this->notify();
}
} }

View File

@ -2,19 +2,28 @@
namespace DesignPatterns\Behavioral\Observer; namespace DesignPatterns\Behavioral\Observer;
/**
* class UserObserver.
*/
class UserObserver implements \SplObserver class UserObserver implements \SplObserver
{ {
/** /**
* This is the only method to implement as an observer. * @var User[]
* It is called by the Subject (usually by SplSubject::notify() ). */
private $changedUsers = [];
/**
* It is called by the Subject, usually by SplSubject::notify()
* *
* @param \SplSubject $subject * @param \SplSubject $subject
*/ */
public function update(\SplSubject $subject) public function update(\SplSubject $subject)
{ {
echo get_class($subject).' has been updated'; $this->changedUsers[] = clone $subject;
}
/**
* @return User[]
*/
public function getChangedUsers(): array
{
return $this->changedUsers;
} }
} }

View File

@ -1,27 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Diagram> <Diagram>
<ID>PHP</ID> <ID>PHP</ID>
<OriginalElement>\DesignPatterns\Behavioral\Observer\User</OriginalElement> <OriginalElement>\DesignPatterns\Behavioral\Observer\UserObserver</OriginalElement>
<nodes> <nodes>
<node x="239.0" y="0.0">\DesignPatterns\Behavioral\Observer\UserObserver</node> <node x="215.0" y="112.0">\DesignPatterns\Behavioral\Observer\UserObserver</node>
<node x="0.0" y="137.0">\DesignPatterns\Behavioral\Observer\User</node> <node x="229.5" y="7.0">\SplObserver</node>
<node x="8.0" y="0.0">\SplSubject</node> <node x="-29.0" y="25.0">\DesignPatterns\Behavioral\Observer\User</node>
</nodes> </nodes>
<notes /> <notes />
<edges> <edges>
<edge source="\DesignPatterns\Behavioral\Observer\User" target="\SplSubject"> <edge source="\DesignPatterns\Behavioral\Observer\UserObserver" target="\SplObserver">
<point x="0.0" y="-74.0" /> <point x="0.0" y="-48.0" />
<point x="0.0" y="43.5" /> <point x="0.0" y="25.5" />
</edge> </edge>
</edges> </edges>
<settings layout="Hierarchic Group" zoom="1.0" x="186.0" y="142.5" /> <settings layout="Hierarchic Group" zoom="1.0" x="58.0" y="91.0" />
<SelectedNodes /> <SelectedNodes />
<Categories> <Categories>
<Category>Fields</Category> <Category>Fields</Category>
<Category>Constants</Category> <Category>Constants</Category>
<Category>Constructors</Category> <Category>Methods</Category>
<Category>Methods</Category> </Categories>
</Categories> <VISIBILITY>private</VISIBILITY>
<VISIBILITY>private</VISIBILITY> </Diagram>
</Diagram>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 45 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 108 KiB