Design Patterns : Observer Pattern

Previous post in the series – Design Patterns : Introduction
Next post in the series – Design Patterns : Singleton Pattern


In the last post, we went around listing the three classifications of design patterns and some common examples of each. We also mentioned that MVC (Model-View-Controller) qualifies more as an architecture pattern rather than a design pattern as it has a broader impact on the application architecture. In this post, let us discuss in detail Observer pattern, which falls under the category of ‘Behavioral Design Patterns’.

The observer design pattern is a software design pattern in which an object, the subject, maintains a list of its dependents, the observers, and notifies them automatically of any state changes. This would be usually done by calling one of their methods. This design pattern is mostly used in implementing distributed event handling systems. In general, observer pattern can be used whenever a subject has to be observed by one or more observers. It defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

The observer pattern is typically used when:-

  • The change of a state in one object must be reflected in another object without keeping the objects tight coupled.
  • The framework we are writing needs to be enhanced in future with new observers with minimal changes.

Example:-

In the following example, an observer is watching the changes in a List of People objects:-


Class MyObserver.java

package observerpattern;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

public class MyObserver implements PropertyChangeListener {

    public MyObserver(MyModel model) {
        model.addChangeListener(this); 
    }

    @Override
    public void propertyChange(PropertyChangeEvent event) {
        System.out.println("Changed property: " + event.getPropertyName() + " [old -> "
            + event.getOldValue() + "] | [new -> " + event.getNewValue() + "]");
    }
}

Class MyModel.java

package observerpattern;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;

public class MyModel {

    public static final String FIRSTNAME = "firstName";
    public static final String LASTNAME = "lastName";
    private List persons = new ArrayList();
    private List listener = new ArrayList();

    public class Person {
        private String firstName;
        private String lastName;

        //constructor for the inner class
        public Person(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }

        //setters and getters for the inner class
        public String getFirstName() {
            return firstName;
        }

        public void setFirstName(String firstName) {
            notifyListeners(this,
                FIRSTNAME,
                this.firstName,
                this.firstName = firstName);
        }

        public String getLastName() {
            return lastName;
        }

        public void setLastName(String lastName) {
            notifyListeners(this,
                LASTNAME,
                this.lastName,
                this.lastName = lastName);
        }
    }

    //setters and getters
    public List getPersons() {
        return persons;
    }

    //public constructor
    public MyModel() {
        // just for testing we hard-code the persons here:
        persons.add(new Person("Harshit", "Shrivastava"));
        persons.add(new Person("Utkarsh", "Shrivastava"));
    }

    private void notifyListeners(Object object, String property, String oldValue, String newValue) {
        for (PropertyChangeListener name : listener) {
            name.propertyChange(new PropertyChangeEvent(this, property, oldValue, newValue));
        }
    }

    public void addChangeListener(PropertyChangeListener newListener) {
        listener.add(newListener);
    }
}

Class ObserverPattern.java

package observerpattern;
import observerpattern.MyModel.Person;

public class ObserverPattern {

    /**
    * @param args the command line arguments
    */
    public static void main(String[] args) {
        MyModel model = new MyModel();
        MyObserver observer = new MyObserver(model);
        //on changing the surname, observer will get notified
        for (Person person : model.getPersons()) {
            person.setLastName(person.getLastName() + "1");
        }

        //on changing the name, observer will get notified
        for (Person person : model.getPersons()) {
            person.setFirstName(person.getFirstName() + "1");
        }
    }
}

Two models of passing data from subject to observer

There are two models of passing data from the subject to the observer when the state is being changed in the subject side – Push Model and Pull Model

  • Push Model: The subjects send detailed information about the change to the observer whether it uses it or not. Because the subject needs to send the detailed information to the observer this might be inefficient when a large amount of data needs to be sent and it is not used. Another aproach would be to send only the information required by the observer. In this case the subject should be able to distinguish between different types of observers and to know the required data of each of them, meaning that the subject layer is more coupled to observer layer.
  • Pull Model: The subject just notifies the observers when a change in his state appears and it’s the responsibility of each observer to pull the required data from the subject. This can be inefficient because the communication is done in 2 steps and problems might appear in multi-threading environments.

Introducing the ‘ChangeManager’

If there are several subjects and observers, the relations between them becomes more complex. Firstly, all might have ‘many to many’ relations which would be more difficult to manage directly. Secondly, the relation between subjects and observers might contain some logic, say, maybe we want to have an observer notified only when all the subjects change their state. In this case we should introduce another object called the ChangeManager.

The ChangeManager would be responsible for following actions:-

  • to maintain the many to many relations between the subjects and their observers.
  • to encapsulate the logic for notifying the observers.
  • to receive notifications from subjects and delegate them to observers (based on the logic it encapsulates)

Basically, the ChangeManager is both an observer, as well as a subject. It is an observer because if gets notified of changes in the subject, and it is a subject because it notify the observers. ChangeManager is an implementation of Mediator pattern.

Typical problems in implementation

  • Many Subjects to Many Observers: In this case the observer needs to be notified not only about the change, but also about the subject with the state changed.
  • Self Consistency of Subject before notification: The subject needs to be consistent before the notification is triggered, else the observer would be refreshed with an old state.

First post in the series – Design Patterns : Introduction
Previous post in the series – Design Patterns : Introduction
Next post in the series – Design Patterns : Singleton Pattern

Advertisements

2 thoughts on “Design Patterns : Observer Pattern

  1. Pingback: Design Patterns : Introduction | Harshit Shrivastava

  2. Pingback: Design Patterns : Singleton Pattern | Harshit Shrivastava

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s