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\UserObserver;
/**
* ObserverTest tests the Observer pattern.
*/
class ObserverTest extends \PHPUnit_Framework_TestCase
{
protected $observer;
protected function setUp()
public function testChangeInUserLeadsToUserObserverBeingNotified()
{
$this->observer = new UserObserver();
}
$observer = new UserObserver();
/**
* Tests the notification.
*/
public function testNotify()
{
$this->expectOutputString('DesignPatterns\Behavioral\Observer\User has been updated');
$subject = new User();
$user = new User();
$user->attach($observer);
$subject->attach($this->observer);
$subject->property = 123;
}
/**
* 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();
$user->changeEmail('foo@bar.com');
$this->assertCount(1, $observer->getChangedUsers());
}
}

View File

@ -3,60 +3,42 @@
namespace DesignPatterns\Behavioral\Observer;
/**
* Observer pattern : The observed object (the subject).
*
* The subject maintains a list of Observers and sends notifications.
* 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
*/
class User implements \SplSubject
{
/**
* user data.
*
* @var array
* @var string
*/
protected $data = array();
private $email;
/**
* observers.
*
* @var \SplObjectStorage
*/
protected $observers;
private $observers;
public function __construct()
{
$this->observers = new \SplObjectStorage();
}
/**
* attach a new observer.
*
* @param \SplObserver $observer
*
* @return void
*/
public function attach(\SplObserver $observer)
{
$this->observers->attach($observer);
}
/**
* detach an observer.
*
* @param \SplObserver $observer
*
* @return void
*/
public function detach(\SplObserver $observer)
{
$this->observers->detach($observer);
}
/**
* notify observers.
*
* @return void
*/
public function changeEmail(string $email)
{
$this->email = $email;
$this->notify();
}
public function notify()
{
/** @var \SplObserver $observer */
@ -64,21 +46,4 @@ class User implements \SplSubject
$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;
/**
* class UserObserver.
*/
class UserObserver implements \SplObserver
{
/**
* This is the only method to implement as an observer.
* It is called by the Subject (usually by SplSubject::notify() ).
* @var User[]
*/
private $changedUsers = [];
/**
* It is called by the Subject, usually by SplSubject::notify()
*
* @param \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"?>
<Diagram>
<ID>PHP</ID>
<OriginalElement>\DesignPatterns\Behavioral\Observer\User</OriginalElement>
<nodes>
<node x="239.0" y="0.0">\DesignPatterns\Behavioral\Observer\UserObserver</node>
<node x="0.0" y="137.0">\DesignPatterns\Behavioral\Observer\User</node>
<node x="8.0" y="0.0">\SplSubject</node>
</nodes>
<notes />
<edges>
<edge source="\DesignPatterns\Behavioral\Observer\User" target="\SplSubject">
<point x="0.0" y="-74.0" />
<point x="0.0" y="43.5" />
</edge>
</edges>
<settings layout="Hierarchic Group" zoom="1.0" x="186.0" y="142.5" />
<SelectedNodes />
<Categories>
<Category>Fields</Category>
<Category>Constants</Category>
<Category>Constructors</Category>
<Category>Methods</Category>
</Categories>
<VISIBILITY>private</VISIBILITY>
</Diagram>
<?xml version="1.0" encoding="UTF-8"?>
<Diagram>
<ID>PHP</ID>
<OriginalElement>\DesignPatterns\Behavioral\Observer\UserObserver</OriginalElement>
<nodes>
<node x="215.0" y="112.0">\DesignPatterns\Behavioral\Observer\UserObserver</node>
<node x="229.5" y="7.0">\SplObserver</node>
<node x="-29.0" y="25.0">\DesignPatterns\Behavioral\Observer\User</node>
</nodes>
<notes />
<edges>
<edge source="\DesignPatterns\Behavioral\Observer\UserObserver" target="\SplObserver">
<point x="0.0" y="-48.0" />
<point x="0.0" y="25.5" />
</edge>
</edges>
<settings layout="Hierarchic Group" zoom="1.0" x="58.0" y="91.0" />
<SelectedNodes />
<Categories>
<Category>Fields</Category>
<Category>Constants</Category>
<Category>Methods</Category>
</Categories>
<VISIBILITY>private</VISIBILITY>
</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