Saturday, May 23, 2009

The observer pattern using PHP

The observer pattern gives you another way to avoid tight coupling between components. This pattern is simple: One object makes itself observable by adding a method that allows another object, the observer, to register itself. When the observable object changes, it sends a message to the registered observers. What those observers do with that information isn't relevant or important to the observable object. The result is a way for objects to talk with each other without necessarily understanding why.
A simple example is a list of users in a system. The code below shows a user list that sends out a message when users are added. This list is watched by a logging observer that puts out a message when a user is added.


interface IObserver {
function onChanged($sender, $args);

interface IObservable {
function addObserver($observer);

class UserList implements IObservable {
private $_observers = array();

public function addCustomer($name) {
foreach( $this->_observers as $obs )
$obs->onChanged( $this, $name );

public function addObserver( $observer ) {
$this->_observers []= $observer;

class UserListLogger implements IObserver {
public function onChanged( $sender, $args ) {
echo( "'$args' added to user list\n" );

$ul = new UserList();
$ul->addObserver( new UserListLogger() );
$ul->addCustomer( "Jack" );

This code defines four elements: two interfaces and two classes. The IObservable interface defines an object that can be observed, and the UserList implements that interface to register itself as observable. The IObserver list defines what it takes to be an observer, and the UserListLogger implements that IObserver interface.

The observable user list and the user list event logger
The observable user list and the user list event logger

If you run this on the command line, you see this output:

% php observer.php
'Jack' added to user list

The test code creates a UserList and adds the UserListLogger observer to it. Then the code adds a customer, and the UserListLogger is notified of that change.
It's critical to realize that the UserList doesn't know what the logger is going to do. There could be one or more listeners that do other things. For example, you may have an observer that sends a message to the new user, welcoming him to the system. The value of this approach is that the UserList is ignorant of all the objects depending on it; it focuses on its job of maintaining the user list and sending out messages when the list changes.
This pattern isn't limited to objects in memory. It's the underpinning of the database-driven message queuing systems used in larger applications.

Design Patterns for PHP

No comments:

Post a Comment