Observer
Scope
Object
Purpose
Behavioral
Intent
Define a one-to-many dependency between objects so that when one object changes state (the Subject), all its dependents (the Observers) are notified and updated automatically.
Applicability
- when an abstraction has two aspects, one dependent on the other
- when a change to one object requires changing others, and you don't know how many objects need to be changed
- when an object should notify other objects without making assumptions about who these objects are
Structure
Consequences
- + modularity: subject and observers may vary independently
- + extensibility: can define and add any number of observers
- + customizability: different observers provide different views of subject
- - unexpected updates: observers don't know about each other
- - update overhead: might need hints
Implementation
- subject-observer mapping
- dangling references
- avoiding observer-specific update protocols: the push and pull models
- registering modifications of interest explicitly
Related pattern
Description
- Problem
- In one place or many places in the application we need to be aware about a system event or an application state change. We'd like to have a standard way of subscribing to listening for system events and a standard way of notifying the interested parties. The notification should be automated after an interested party subscribed to the system event or application state change. There should be a way to unsubscribe, too.
- Forces
- Observers and observables probably should be represented by objects. The observer objects will be notified by the observable objects.
- Solution
- After subscribing the listening objects will be notified by a way of method call.
- Loose coupling
- When two objects are loosely coupled, they can interact, but they have very little knowledge of each other. Strive for loosely coupled designs between objects that interact.
- The only thing that Subject knows about an observer is that it implements a certain interface
- We can add new observers at any time
- We never need to modify the subject to add new types of observers
- We can reuse subjects or observers independently of each other
- Changes to either the subject or an observer will not affect the other
Examples
The Observer pattern is used extensively in Java. E.g. in the following piece of code
button
is the SubjectMyListener
is the ObserveractionPerformed()
is the equivalent toupdate()
JButton button = new JButton("Click me!");
button.addActionListener(new MyListener());
class MyListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
...
}
}
Another example is the PropertyChangeSupport
. The Component
class uses a PropertyChangeSupport
object to let interested observers register for notification of changes in the properties of labels, panels, and other GUI components.
Can you find the Subject
, Observer
and update()
in the above class diagram?
Component
is the SubjectPropertyChangeListener
is the ObserverpropertyChange()
is the equivalent toupdate()
Cost
This pattern can be tricky if you do not beware. Beware the data representing the state changes of the subject can evolve without changing the interfaces. If you only transmit a string, the pattern could become very expensive if at least one new observer needs also a state code. You should use a mediator unless you know the implementation of the subject state will never change.
Creation
This pattern has a cost to create.
Maintenance
This pattern can be expensive to maintain.
Removal
This pattern has a cost to remove too.
Advises
- Put the subject and observer term in the name of the subject and the observer classes to indicate the use of the pattern to the other developers.
- To improve performances, you can only send to the observers the difference of states instead of the new state. The observers can only update following the changed part of the subject instead of all the state of the subject.
Implementations
// Main Class
package {
import flash.display.MovieClip;
public class Main extends MovieClip {
private var _cs:ConcreteSubject = new ConcreteSubject();
private var _co1:ConcreteObserver1 = new ConcreteObserver1();
private var _co2:ConcreteObserver2 = new ConcreteObserver2();
public function Main() {
_cs.registerObserver(_co1);
_cs.registerObserver(_co2);
_cs.changeState(10);
_cs.changeState(99);
_cs.unRegisterObserver(_co1);
_cs.changeState(17);
_co1 = null;
}
}
}
// Interface Subject
package {
public interface ISubject {
function registerObserver(o:IObserver):void;
function unRegisterObserver(o:IObserver):void;
function updateObservers():void;
function changeState(newState:uint):void;
}
}
// Interface Observer
package {
public interface IObserver {
function update(newState:uint):void;
}
}
// Concrete Subject
package {
public class ConcreteSubject implements ISubject {
private var _observersList:Array = new Array();
private var _currentState:uint;
public function ConcreteSubject() {
}
public function registerObserver(o:IObserver):void {
_observersList.push( o );
_observersList[_observersList.length-1].update(_currentState); // update newly registered
}
public function unRegisterObserver(o:IObserver):void {
_observersList.splice( _observersList.indexOf( o ), 1 );
}
public function updateObservers():void {
for( var i:uint = 0; i<_observersList.length; i++) {
_observersList[i].update(_currentState);
}
}
public function changeState(newState:uint):void {
_currentState = newState;
updateObservers();
}
}
}
// Concrete Observer 1
package {
public class ConcreteObserver1 implements IObserver {
public function ConcreteObserver1() {
}
public function update(newState:uint):void {
trace( "co1: "+newState );
}
// other Observer specific methods
}
}
// Concrete Observer 2
package {
public class ConcreteObserver2 implements IObserver {
public function ConcreteObserver2() {
}
public function update(newState:uint):void {
trace( "co2: "+newState );
}
// other Observer specific methods
}
}
Traditional Method
C# and the other .NET Framework languages do not typically require a full implementation of the Observer pattern using interfaces and concrete objects. Here is an example of using them, however.
using System;
using System.Collections;
namespace Wikipedia.Patterns.Observer
{
// IObserver --> interface for the observer
public interface IObserver
{
// called by the subject to update the observer of any change
// The method parameters can be modified to fit certain criteria
void Update(string message);
}
public class Subject
{
// use array list implementation for collection of observers
private ArrayList observers;
// constructor
public Subject()
{
observers = new ArrayList();
}
public void Register(IObserver observer)
{
// if list does not contain observer, add
if (!observers.Contains(observer))
{
observers.Add(observer);
}
}
public void Unregister(IObserver observer)
{
// if observer is in the list, remove
observers.Remove(observer);
}
public void Notify(string message)
{
// call update method for every observer
foreach (IObserver observer in observers)
{
observer.Update(message);
}
}
}
// Observer1 --> Implements the IObserver
public class Observer1 : IObserver
{
public void Update(string message)
{
Console.WriteLine("Observer1:" + message);
}
}
// Observer2 --> Implements the IObserver
public class Observer2 : IObserver
{
public void Update(string message)
{
Console.WriteLine("Observer2:" + message);
}
}
// Test class
public class ObserverTester
{
[STAThread]
public static void Main()
{
Subject mySubject = new Subject();
IObserver myObserver1 = new Observer1();
IObserver myObserver2 = new Observer2();
// register observers
mySubject.Register(myObserver1);
mySubject.Register(myObserver2);
mySubject.Notify("message 1");
mySubject.Notify("message 2");
}
}
}
Using Events
The alternative to using concrete and abstract observers and publishers in C# and other .NET Framework languages, such as Visual Basic, is to use events. The event model is supported via delegates that define the method signature that should be used to capture events. Consequently, delegates provide the mediation otherwise provided by the abstract observer, the methods themselves provide the concrete observer, the concrete subject is the class defining the event, and the subject is the event system built into the base class library. It is the preferred method of accomplishing the Observer pattern in.NET applications.
using System;
// First, declare a delegate type that will be used to fire events.
// This is the same delegate as System.EventHandler.
// This delegate serves as the abstract observer.
// It does not provide the implementation, but merely the contract.
public delegate void EventHandler(object sender, EventArgs e);
// Next, declare a published event. This serves as the concrete subject.
// Note that the abstract subject is handled implicitly by the runtime.
public class Button
{
// The EventHandler contract is part of the event declaration.
public event EventHandler Clicked;
// By convention,.NET events are fired from descendant classes by a virtual method,
// allowing descendant classes to handle the event invocation without subscribing
// to the event itself.
protected virtual void OnClicked(EventArgs e)
{
if (Clicked != null)
Clicked(this, e); // implicitly calls all observers/subscribers
}
}
// Then in an observing class, you are able to attach and detach from the events:
public class Window
{
private Button okButton;
public Window()
{
okButton = new Button();
// This is an attach function. Detaching is accomplished with -=.
// Note that it is invalid to use the assignment operator - events are multicast
// and can have multiple observers.
okButton.Clicked += new EventHandler(okButton_Clicked);
}
private void okButton_Clicked(object sender, EventArgs e)
{
// This method is called when Clicked(this, e) is called within the Button class
// unless it has been detached.
}
}
Handy implementation
You can implement this pattern in Java like this:
// Observer pattern -- Structural example
// @since JDK 5.0
import java.util.ArrayList;
// "Subject"
abstract class Subject {
// Fields
private ArrayList<Observer> observers = new ArrayList<Observer>();
// Methods
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer o : observers)
o.update();
}
}
// "ConcreteSubject"
class ConcreteSubject extends Subject {
// Fields
private String subjectState;
// Properties
public String getSubjectState() {
return subjectState;
}
public void setSubjectState(String value) {
subjectState = value;
}
}
// "Observer"
abstract class Observer {
// Methods
abstract public void update();
}
// "ConcreteObserver"
class ConcreteObserver extends Observer {
// Fields
private String name;
private String observerState;
private ConcreteSubject subject;
// Constructors
public ConcreteObserver(ConcreteSubject subject, String name) {
this.subject = subject;
this.name = name;
//subject.attach(this);
}
// Methods
public void update() {
observerState = subject.getSubjectState();
System.out.printf("Observer %s's new state is %s\n", name, observerState);
}
}
// Client test
public class Client {
public static void main(String[] args) {
// Configure Observer structure
ConcreteSubject s = new ConcreteSubject();
s.attach(new ConcreteObserver(s, "A"));
s.attach(new ConcreteObserver(s, "B"));
s.attach(new ConcreteObserver(s, "C"));
// Change subject and notify observers
s.setSubjectState("NEW");
s.notifyObservers();
}
}
Built-in support
The Java JDK has several implementations of this pattern: application in Graphical User Interfaces such as in the AWT toolkit, Swing etc. In Swing, whenever a user clicks a button or adjusts a slider, many objects in the application may need to react to the change. Swing refers to interested clients (observers) as "listeners" and lets you register as many listeners as you like to be notified of a component's events.
MVC is more M(VC) in Swing, i.e. View and Controller are tightly coupled; Swing does not divide Views from Controllers. MVC supports n-tier development, i.e. loosely coupled layers (see below) that can change independently and that may even execute on different machines.
There is also a built-in support for the Observer pattern. All one has to do is extend java.util.Observable (the Subject) and tell it when to notify the java.util.Observer s. The API does the rest for you. You may use either push or pull style of updating your observers.
java.util.Observable
is a class while java.util.Observer
is an interface.
public void setValue(double value) {
this.value = value;
setChanged();
notifyObservers();
}
Note that you have to call setChanged()
so that the Observable
code will broadcast the change.
The notifyObservers()
method calls the update()
method of each registered observer. The update()
method is a requirement for implementers of the Observer
Interface.
// Observer pattern -- Structural example
import java.util.Observable;
import java.util.Observer;
// "Subject"
class ConcreteSubject extends Observable {
// Fields
private String subjectState;
// Methods
public void dataChanged() {
setChanged();
notifyObservers(); // use the pull method
}
// Properties
public String getSubjectState() {
return subjectState;
}
public void setSubjectState(String value) {
subjectState = value;
dataChanged();
}
}
// "ConcreteObserver"
import java.util.Observable;
import java.util.Observer;
class ConcreteObserver implements Observer {
// Fields
private String name;
private String observerState;
private Observable subject;
// Constructors
public ConcreteObserver(Observable subject, String name) {
this.subject = subject;
this.name = name;
subject.addObserver(this);
}
// Methods
public void update(Observable subject, Object arg) {
if (subject instanceof ConcreteSubject) {
ConcreteSubject subj = (ConcreteSubject)subject;
observerState = subj.getSubjectState();
System.out.printf("Observer %s's new state is %s\n", name, observerState);
}
}
}
// Client test
public class Client {
public static void main(String[] args) {
// Configure Observer structure
ConcreteSubject s = new ConcreteSubject();
new ConcreteObserver(s, "A");
new ConcreteObserver(s, "B");
new ConcreteObserver(s, "C");
// Change subject and notify observers
s.setSubjectState("NEW");
}
}
Keyboard handling
Below is an example written in Java that takes keyboard input and treats each input line as an event. The example is built upon the library classes java.util.Observer
and java.util.Observable
. When a string is supplied from System.in, the method notifyObservers
is then called, in order to notify all observers of the event's occurrence, in the form of an invocation of their 'update' methods - in our example, ResponseHandler.update(...)
.
The file MyApp.java
contains a main()
method that might be used in order to run the code.
/* Filename : EventSource.java */
package org.wikibooks.obs;
import java.util.Observable; // Observable is here
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class EventSource extends Observable implements Runnable {
@Override
public void run() {
try {
final InputStreamReader isr = new InputStreamReader(System.in);
final BufferedReader br = new BufferedReader(isr);
while (true) {
String response = br.readLine();
setChanged();
notifyObservers(response);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/* Filename : ResponseHandler.java */
package org.wikibooks.obs;
import java.util.Observable;
import java.util.Observer; /* this is Event Handler */
public class ResponseHandler implements Observer {
private String resp;
public void update(Observable obj, Object arg) {
if (arg instanceof String) {
resp = (String) arg;
System.out.println("\nReceived Response: " + resp );
}
}
}
/* Filename : MyApp.java */
/* This is the main program */
package org.wikibooks.obs;
public class MyApp {
public static void main(String[] args) {
System.out.println("Enter Text >");
// create an event source - reads from stdin
final EventSource eventSource = new EventSource();
// create an observer
final ResponseHandler responseHandler = new ResponseHandler();
// subscribe the observer to the event source
eventSource.addObserver(responseHandler);
// starts the event thread
Thread thread = new Thread(eventSource);
thread.start();
}
}
The Java implementation of the Observer pattern has pros and cons:
Pros
- It hides many of the details of the Observer pattern
- It can be used both pull and push ways.
Cons
- Because
Observable
is a class, you have to subclass it; you can’t add on theObservable
behavior to an existing class that subclasses another superclass (fails the programming to interfaces principle). If you can’t subclassObservable
, then use delegation, i.e. provide your class with an Observable object and have your class forward key method calls to it. - Because
setChanged()
is protected, you can’t favour composition over inheritance.
class STUDENT
<?php
class Student implements SplObserver {
protected $type = "Student";
private $name;
private $address;
private $telephone;
private $email;
private $_classes = array();
public function __construct($name)
{
$this->name = $name;
}
public function GET_type()
{
return $this->type;
}
public function GET_name()
{
return $this->name;
}
public function GET_email()
{
return $this->email;
}
public function GET_telephone()
{
return $this->telephone;
}
public function update(SplSubject $object)
{
$object->SET_log("Comes from ".$this->name.": I'm a student of ".$object->GET_materia());
}
}
?>
class TEACHER
<?php
class Teacher implements SplObserver {
protected $type = "Teacher";
private $name;
private $address;
private $telephone;
private $email;
private $_classes = array();
public function __construct($name)
{
$this->name = $name;
}
public function GET_type()
{
return $this->type;
}
public function GET_name()
{
return $this->name;
}
public function GET_email()
{
return $this->email;
}
public function GET_telephone()
{
return $this->name;
}
public function update(SplSubject $object)
{
$object->SET_log("Comes from ".$this->name.": I teach in ".$object->GET_materia());
}
}
?>
Class SUBJECT
<?php
class Subject implements SplSubject {
private $name_materia;
private $_observers = array();
private $_log = array();
function __construct($name)
{
$this->name_materia = $name;
$this->_log[] = "Subject $name was included";
}
/* Add an observer */
public function attach(SplObserver $classes) {
$this->_classes[] = $classes;
$this->_log[] = " The ".$classes->GET_type()." ".$classes->GET_name()." was included";
}
/* Remove an observer */
public function detach(SplObserver $classes) {
foreach ($this->_classes as $key => $obj) {
if ($obj == $classes) {
unset($this->_classes[$key]);
$this->_log[] = " The ".$classes->GET_type()." ".$classes->GET_name()." was removed";
}
}
}
/* Notificate an observer */
public function notify(){
foreach ($this->_classes as $classes){
$classes->update($this);
}
}
public function GET_materia()
{
return $this->name_materia;
}
function SET_log($valor)
{
$this->_log[] = $valor ;
}
function GET_log()
{
return $this->_log;
}
}
?>
Application
<?php
require_once("teacher.class.php");
require_once("student.class.php");
require_once("subject.class.php");
$subject = new Subject("Math");
$marcus = new Teacher("Marcus Brasizza");
$rafael = new Student("Rafael");
$vinicius = new Student("Vinicius");
// Include observers in the math Subject
$subject->attach($rafael);
$subject->attach($vinicius);
$subject->attach($marcus);
$subject2 = new Subject("English");
$renato = new Teacher("Renato");
$fabio = new Student("Fabio");
$tiago = new Student("Tiago");
// Include observers in the english Subject
$subject2->attach($renato);
$subject2->attach($vinicius);
$subject2->attach($fabio);
$subject2->attach($tiago);
// Remove the instance "Rafael from subject"
$subject->detach($rafael);
// Notify both subjects
$subject->notify();
$subject2->notify();
echo "First Subject <br>";
echo "<pre>";
print_r($subject->GET_log());
echo "</pre>";
echo "<hr>";
echo "Second Subject <br>";
echo "<pre>";
print_r($subject2->GET_log());
echo "</pre>";
?>
OUTPUT
First Subject
Array
(
[0] => Subject Math was included
[1] => The Student Rafael was included
[2] => The Student Vinicius was included
[3] => The Teacher Marcus Brasizza was included
[4] => The Student Rafael was removed
[5] => Comes from Vinicius: I'm a student of Math
[6] => Comes from Marcus Brasizza: I teach in Math
)
Second Subject
Array
(
[0] => Subject English was included
[1] => The Teacher Renato was included
[2] => The Student Vinicius was included
[3] => The Student Fabio was included
[4] => The Student Tiago was included
[5] => Comes from Renato: I teach in English
[6] => Comes from Vinicius: I'm a student of English
[7] => Comes from Fabio: I'm a student of English
[8] => Comes from Tiago: I'm a student of English
)
The observer pattern in Python:
class AbstractSubject:
def register(self, listener):
raise NotImplementedError("Must subclass me")
def unregister(self, listener):
raise NotImplementedError("Must subclass me")
def notify_listeners(self, event):
raise NotImplementedError("Must subclass me")
class Listener:
def __init__(self, name, subject):
self.name = name
subject.register(self)
def notify(self, event):
print self.name, "received event", event
class Subject(AbstractSubject):
def __init__(self):
self.listeners = []
self.data = None
def getUserAction(self):
self.data = raw_input('Enter something to do:')
return self.data
# Implement abstract Class AbstractSubject
def register(self, listener):
self.listeners.append(listener)
def unregister(self, listener):
self.listeners.remove(listener)
def notify_listeners(self, event):
for listener in self.listeners:
listener.notify(event)
if __name__=="__main__":
# make a subject object to spy on
subject = Subject()
# register two listeners to monitor it.
listenerA = Listener("<listener A>", subject)
listenerB = Listener("<listener B>", subject)
# simulated event
subject.notify_listeners ("<event 1>")
# outputs:
# <listener A> received event <event 1>
# <listener B> received event <event 1>
action = subject.getUserAction()
subject.notify_listeners(action)
#Enter something to do:hello
# outputs:
# <listener A> received event hello
# <listener B> received event hello
The observer pattern can be implemented more succinctly in Python using function decorators.
In Ruby, use the standard Observable mixin. For documentation and an example, see http://www.ruby-doc.org/stdlib/libdoc/observer/rdoc/index.html