29.4 Observer
Observer is one of the most useful design patterns for developing large-scale object-oriented applications. It allows you, with the use of messages, to interconnect objects without their having to know anything about each other. At the heart of the Observer pattern are two main actors: observers and subjects. Observer objects find subject objects interesting and need to know when the subject changes. Typically, multiple observers monitor a single subject.
Listing 29.3 contains a simple implementation of the Observer pattern.
Listing 29.3 Observer pattern
<?php interface Message { static function getType(); }; interface Observer { function notifyMsg(Message $msg); }; class Subject { private $observers = array(); function registerObserver(Observer $observer, $msgType) { $this->observers[$msgType][] = $observer; } private function notifyMsg(Message $msg) { @$observers = $this->observers[$msg->getType()]; if(!$observers) { return; } foreach($observers as $observer) { $observer->notifyMsg($msg); } } function someMethod() { //fake some task sleep(1); //notify observers $this->notifyMsg(new HelloMessage("Zeev")); } } class HelloMessage implements Message { private $name; function __construct($name) { $this->name = $name; } function getMsg() { return "Hello, $this->name!"; } static function getType() { return "HELLO_TYPE"; } } class MyObserver implements Observer { function notifyMsg(Message $msg) { if ($msg instanceof HelloMessage) { print $msg->getMsg(); } } } $subject = new Subject(); $observer = new MyObserver(); $subject->registerObserver($observer, HelloMessage::getType()); $subject->someMethod(); ?>
The beauty in the Observer pattern is that it allows subject objects to activate Observer objects without the subjects having any knowledge about the objects that observe them other than that they support the notification interface. The Observer pattern enables developers to connect dependent objects in different parts of the application, dynamically and as necessary, without having to provide specialized APIs for each type of dependency. It also allows different Observer objects to select what kind of information interests them without having to change any code in the subject object.
One thing to worry about when implementing Observer is cyclic notification paths. An object may both observe other objects and be observed by other objectsthat is, be both a Subject and an Observer. If two objects observe each other and deliver messages that trigger another message in their observing object, an endless loop occurs. In order to avoid it, it's best if you avoid delivering notification messages in your notification handler. If it's not possible, try to create a simple, one-sided flow of information, which will prevent cyclic dependencies.