Easy Tutorial
❮ Strategy Pattern Iterator Pattern ❯

Observer Pattern

The Observer Pattern is used when there is a one-to-many relationship between objects. For example, if one object is modified, its dependent objects are automatically notified. The Observer Pattern is a behavioral pattern.

Introduction

Intent: Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

Main Solution: The problem of notifying other objects about a state change of an object, considering ease of use and low coupling for high collaboration.

When to Use: When the state of one object (the subject) changes, all its dependent objects (observers) should be notified and updated.

How to Solve: Use object-oriented techniques to weaken this dependency.

Key Code: An ArrayList in the abstract class to store observers.

Examples:

  1. In an auction, the auctioneer observes the highest bid and notifies other bidders.
  2. In "Journey to the West," Sun Wukong asks the Bodhisattva to subdue the Red Boy. The Bodhisattva sprinkles water on the ground, summoning a turtle, which is an observer watching the Bodhisattva's action.

Advantages:

  1. Observer and subject are loosely coupled.
  2. Establishes a trigger mechanism.

Disadvantages:

  1. If an observed object has many direct and indirect observers, notifying all of them can take a lot of time.
  2. Circular dependencies between observers and the subject can trigger cyclic calls, potentially causing system crashes.
  3. Observers have no mechanism to know how the observed object changed, only that it has changed.

Usage Scenarios:

Notes:

  1. Java already has support classes for the Observer Pattern.
  2. Avoid circular references.
  3. If executed sequentially, an error in one observer can block the system; asynchronous execution is generally preferred.

Implementation

The Observer Pattern uses three classes: Subject, Observer, and Client. The Subject object has methods to bind and unbind observers to the Client object. We create the Subject class, Observer abstract class, and concrete classes extending the Observer abstract class.

ObserverPatternDemo, our demonstration class, uses Subject and concrete class objects to demonstrate the Observer Pattern.

Step 1

Create the Subject class.

Subject.java

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

public class Subject {

   private List<Observer> observers 
      = new ArrayList<Observer>();
   private int state;

   public int getState() {
      return state;
   }

   public void setState(int state) {
      this.state = state;
      notifyAllObservers();
   }

   public void attach(Observer observer){
      observers.add(observer);      
   }

   public void notifyAllObservers(){
      for (Observer observer : observers) {
         observer.update();
      }
   }  
}

Step 2

Create the Observer class.

Observer.java

public abstract class Observer {
   protected Subject subject;
   public abstract void update();
}

Step 3

Create concrete observer classes.

BinaryObserver.java

public class BinaryObserver extends Observer{

   public BinaryObserver(Subject subject){
      this.subject = subject;
      this.subject.attach(this);
   }

   @Override
   public void update() {
      System.out.println( "Binary String: " 
      + Integer.toBinaryString( subject.getState() ) ); 
   }
}

OctalObserver.java

public class OctalObserver extends Observer{

   public OctalObserver(Subject subject){
      this.subject = subject;
      this.subject.attach(this);
   }

   @Override
   public void update() {
     System.out.println( "Octal String: " 
     + Integer.toOctalString( subject.getState() ) ); 
   }
}

HexaObserver.java

public class HexaObserver extends Observer{

   public HexaObserver(Subject subject){
      this.subject = subject;
      this.subject.attach(this);
   }

   @Override
   public void update() {
      System.out.println( "Hex String: " 
      + Integer.toHexString( subject.getState() ).toUpperCase() ); 
   }
}

Step 4

Use Subject and concrete observer objects.

ObserverPatternDemo.java

public class ObserverPatternDemo {
   public static void main(String[] args) {
      Subject subject = new Subject();

      new HexaObserver(subject);
      new OctalObserver(subject);
      new BinaryObserver(subject);

      System.out.println("First state change: 15");   
      subject.setState(15);
      System.out.println("Second state change: 10");  
      subject.setState(10);
   }
}

Step 5

Execute the program, outputting the following results:

First state change: 15
Hex String: F
Octal String: 17
Binary String: 1111
Second state change: 10
Hex String: A
Octal String: 12
Binary String: 1010
❮ Strategy Pattern Iterator Pattern ❯