The Observer Pattern

0
388
Observer pattern

The Observer pattern is a one to many relationship where the observers are notified of a state change from an object.

A common way to think of this is as a publish and subscribe model. There is a publisher who has information to send. You register with the publisher to be a subscriber to listen in on what he has to say. Periodically, the subscribers are notified of information that is available.

In the code below, we have a Subject and Observer. The Observers register with the Subject if they want to be notified. This is an in-process way in PHP to do the Observer pattern. By in-process I mean that everything runs within one process as opposed to running out of process and even remote process.

When running PHP scripts on a HTTP server like Apache, you are running in-process. In the case where you want to run out of process, you need to use something like Java RMI or Microsoft COM. For remote procedure call (RPC) you can use Microsoft DCOM, JSON-RPC, XML-RPC, SOAP.

In the RPC case, the Subject would be running on one machine and the Observers would be running on many machines. In the in-process case, both Subject and Observer instances are running on one machine in one process.

The Observer Pattern Code

Both Subject and Observer have a unique identifier. This can be a name, number, anything that uniquely identifies each object.

Subjects keep an array of references to Observers. A subject knows how to register, unregister, list, and notify Observers. Observers have an event to be called notifying them when some data is available from the Subject.

  1. function EchoLine($str, $html=true) {
  2.   $out = ($html) ? $str . "<br>" : $str . "\n";
  3.   echo $out;
  4. }
  5.  
  6. class Subject {
  7.   private $id;
  8.   private $observers;
  9.  
  10.   function __construct($id) {
  11.     $this->id = $id;
  12.     $this->observers = array();
  13.   }
  14.   function GetId() {
  15.     return($this->id);
  16.   }
  17.   function RegisterObserver($observer) {
  18.     $id = $observer->GetId();
  19.     if (array_key_exists($id, $this->observers)) {
  20.       throw new Exception("Cannot register. Observer key already exists.");
  21.     }
  22.     $this->observers[$id] = $observer;
  23.   }
  24.   function UnregisterObserver($observer) {
  25.     $id = $observer->GetId();
  26.     if (!array_key_exists($id, $this->observers)) {
  27.       throw new Exception("Cannot unregister. Observer key does not exist.");
  28.     }
  29.     unset($this->observers[$id]);
  30.   }
  31.   function UnregisterAllObservers() {
  32.     foreach($this->observers as $observer) {
  33.       $id = $observer->GetId();
  34.       $this->UnregisterObserver($id);
  35.     }
  36.   }
  37.   function ListAllObservers() {
  38.     if (count($this->observers) <= 0) {
  39.       EchoLine("Empty list.");
  40.       return;
  41.     }
  42.     foreach($this->observers as $observer) {
  43.       $id = $observer->GetId();
  44.       EchoLine($id);
  45.     }
  46.   }
  47.   function NotifyObservers($msg) {
  48.     foreach($this->observers as $observer) {
  49.       $observer->EventNotify($msg);
  50.     }
  51.   }
  52. }
  53.  
  54. class Observer {
  55.   private $id;
  56.  
  57.   function __construct($id) {
  58.     $this->id = $id;
  59.   }
  60.   function GetId() {
  61.     return($this->id);
  62.   }
  63.   function EventNotify($msg) {
  64.     EchoLine($this->id . " received message " . $msg);
  65.   }
  66. }

Demo Code

  1. try {
  2.   EchoLine("Creating subject and observers...");
  3.   $subject = new Subject("Student Alert");
  4.   $observer1 = new Observer("Bill Jones");
  5.   $observer2 = new Observer("Sally Flanigan");
  6.  
  7.   EchoLine("Registering...");
  8.   $subject->RegisterObserver($observer1);
  9.   $subject->RegisterObserver($observer2);
  10.   $subject->ListAllObservers();
  11.  
  12.   EchoLine("Removing all observers...");
  13.   $subject->UnregisterAllObservers();
  14.   $subject->ListAllObservers();
  15.  
  16.   EchoLine("Registering...");
  17.   $subject->RegisterObserver($observer1);
  18.   $subject->RegisterObserver($observer2);
  19.  
  20.   EchoLine("Notifying observers...");
  21.   $subject->NotifyObservers("Hello!");
  22.  
  23.   EchoLine("Removing all observers...");
  24.   $subject->UnregisterObserver($observer1);
  25.   $subject->UnregisterObserver($observer2);
  26.   $subject->ListAllObservers();
  27.  
  28.   EchoLine("Deleting subject and observers...");
  29.   unset($subject);
  30.   unset($observer1);
  31.   unset($observer2);
  32.  
  33. } catch (Exception $e) {
  34.   EchoLine("Exception: " . $e->getMessage());
  35. }

Of Interest