Observer Design Pattern - Walking Techie

Blog about Java programming, Design Pattern, and Data Structure.

Sunday, August 7, 2016

Observer Design Pattern

The Observer Pattern defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically. This pattern is part of Behavioral design pattern.

Lets, understand this pattern with real world scenario.

To understand the Observer pattern, first need to understand Subject and Observer.

Subject and Observer can easily be understand by newspaper or magazine subscriptions work:

  1. A newspaper publisher(Subject) goes into business and begins publishing newspapers.
  2. You(Observer) subscribe(or register) to a particular publisher, and every time there’s a new edition it gets delivered to you. As long as you remain a subscriber, you get new newspapers.
  3. You unsubscribe when you don’t want papers anymore, and they stop being delivered.
  4. While the publisher remains in business, people, hotels, airlines, and other businesses constantly subscribe and unsubscribe to the newspaper.

Implementation

We are taking simple example of implementation of observer design pattern.

  • We have Subject interface, having method to register, remove/ unregister user and notify user when object changes state.
  • We have concrete class DecimalData have implemented Subject interface.
  • we have DisplayElement interface having display method to display formatted value on the screen.
  • We have Observer interface and all concrete classes BinaryObserver ,OctalObserver, and HexObserver have implemented Observer and DisplayElement interfaces.
  • ObserverPatternDemo class will test the observer design pattern.

UML:

Observer Design Pattern

Step 1

Create Subject interface.

package com.walkingtechie.observer;

public interface Subject {
 /*
  * Both of these methods take an Observer as an argument; that is, the
  * Observer to be registered or removed
  */
 public void registerObserver(Observer o);

 public void removeObserver(Observer o);

 /*
  * This method is called to notify all observers when the Subject’s state
  * has changed.
  */
 public void notifyObserver();
}

Step 2

Create Observer interface.

package com.walkingtechie.observer;

public interface Observer {
 /*
  * The Observer interface is implemented by all observers, so they all have
  * to implement the update() method.
  */
 public void update();
}

Step 3

Create DisplayElement interface to display data on screen.

package com.walkingtechie.observer;

public interface DisplayElement {
 /*
  * The DisplayElement interface just includes one method, display(), that we
  * will call when the display element needs to be displayed.
  */
 public void display();
}

Step 4

Create concrete class DecimalData implementing Subject interface.

package com.walkingtechie.observer;

import java.util.ArrayList;
import java.util.List;

public class DecimalData implements Subject {
 // ArrayList to hold the Observers, and we create it in the constructor.
 private List<Observer> observers;
 private int decimalValue;

 public DecimalData() {
  observers = new ArrayList<Observer>();
 }

 // When an observer registers, we just add it to the end of the list.
 @Override
 public void registerObserver(Observer o) {
  observers.add(o);
 }

 // when an observer wants to unregister, we just take it off the list.
 @Override
 public void removeObserver(Observer o) {
  int index = observers.indexOf(o);
  if (index >= 0) {
   observers.remove(index);
  }
 }

 /*
  * tell all the observers about the state. Because they are all Observers,
  * we know they all implement update(), so we know how to notify them.
  */
 @Override
 public void notifyObserver() {
  for (Observer observer : observers) {
   observer.update();
  }
 }

 // notify the Observers when decimal value change , means sate of object
 // changed.
 public void valuesChanged() {
  notifyObserver();
 }

 public int getDecimalValue() {
  return decimalValue;
 }

 // we’re going to use this method to test our display elements
 public void setDecimalValue(int decimalValue) {
  this.decimalValue = decimalValue;
  valuesChanged();
 }
}

Step 5

Create concrete class that is implementing Observer and DisplayElement interface.

package com.walkingtechie.observer;

public class BinaryObserver implements Observer, DisplayElement {
 private Subject decimalSubject;
 private int decimalValue;

 public BinaryObserver(Subject decimalSubject) {
  this.decimalSubject = decimalSubject;
  decimalSubject.registerObserver(this);
 }

 @Override
 public void update() {
  DecimalData decimalData = null;
  if (decimalSubject instanceof DecimalData) {
   decimalData = (DecimalData) decimalSubject;
   decimalValue = decimalData.getDecimalValue();
  }
  display();
 }

 /*
  * The display() method just prints out the most recent decimal value in
  * binary.
  */
 @Override
 public void display() {
  System.out.println("Binary String: "
    + Integer.toBinaryString(decimalValue));
 }
}
package com.walkingtechie.observer;

public class OctalObserver implements Observer, DisplayElement {
 private Subject decimalSubject;
 private int decimalValue;

 public OctalObserver(Subject decimalSubject) {
  this.decimalSubject = decimalSubject;
  decimalSubject.registerObserver(this);
 }

 @Override
 public void update() {
  DecimalData decimalData = null;
  if (decimalSubject instanceof DecimalData) {
   decimalData = (DecimalData) decimalSubject;
   decimalValue = decimalData.getDecimalValue();
  }
  display();
 }

 /*
  * The display() method just prints out the most recent decimal value in
  * octal.
  */
 @Override
 public void display() {
  System.out.println("Octal String: "
    + Integer.toOctalString(decimalValue));
 }
}
package com.walkingtechie.observer;

public class HexObserver implements Observer, DisplayElement {
 private Subject decimalSubject;
 private int decimalValue;

 public HexObserver(Subject decimalSubject) {
  this.decimalSubject = decimalSubject;
  decimalSubject.registerObserver(this);
 }

 @Override
 public void update() {
  DecimalData decimalData = null;
  if (decimalSubject instanceof DecimalData) {
   decimalData = (DecimalData) decimalSubject;
   decimalValue = decimalData.getDecimalValue();
  }
  display();
 }

 /*
  * The display() method just prints out the most recent decimal value in
  * hexadecimal.
  */
 @Override
 public void display() {
  System.out.println("Hex String: " + Integer.toHexString(decimalValue));
 }
}

Step 6

Create ObserverPatternDemo class to use DecimalData and concrete objects to test observer design pattern.

package com.walkingtechie.observer;

public class ObserverPatternDemo {

 public static void main(String[] args) {
  // First, create the DecimalData object.
  DecimalData decimalData = new DecimalData();

  /*
   * Create the three format Object and pass them the DecimalData object.
   */

  BinaryObserver binaryObserver = new BinaryObserver(decimalData);
  OctalObserver octalObserver = new OctalObserver(decimalData);
  HexObserver hexObserver = new HexObserver(decimalData);

  // set Decimal Value
  decimalData.setDecimalValue(24);
  System.out.println("\nNow, Data is changed.\n");
  // Now, new decimal value
  decimalData.setDecimalValue(124);

 }
}

Output of the above program shown below.

Binary String: 11000
Octal String: 30
Hex String: 18

Now, Data is changed.

Binary String: 1111100
Octal String: 174
Hex String: 7c

The Observer Pattern is one of the most heavily used patterns in the JDK, some of implementations are:

  • java.util.EventListener in Swing
  • javax.servlet.http.HttpSessionBindingListener
  • javax.servlet.http.HttpSessionAttributeListener

Design Principle

Strive for loosely coupled designs between objects that interact.

Loosely coupled designs allow us to build flexible OO systems that can handle change because they minimize the inter dependency between objects.

5 comments :

  1. This comment has been removed by the author.

    ReplyDelete
  2. Awesome article!! Good explanation with an easy example code.

    ReplyDelete
    Replies
    1. Thank you, It will motivate me to write more post.

      Delete
  3. I am looking for and I love to post a comment that "The content of your post is awesome" Great work! Modern Java EE Design Patterns PDF

    ReplyDelete
  4. factorial hundred In the last few days, the “factorial of 100” is one of the top subjects and a lot of maths geeks compute it using voice assistants such as Alexa, Shiri, etc.
    factorial hundred In the last few days, the “factorial of 100” is one of the top subjects and a lot of maths geeks compute it using voice assistants such as Alexa, Shiri, etc.
    factorial hundred In the last few days, the “factorial of 100” is one of the top subjects and a lot of maths geeks compute it using voice assistants such as Alexa, Shiri, etc.


    ReplyDelete