Observer pattern


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

Introduction

Intent:Define a one-to-many dependency relationship between objects. When the state of an object changes, all objects that depend on it will Get notified and automatically updated.

Mainly solves: The problem of notifying other objects of status changes of an object, and taking into account ease of use and low coupling to ensure a high degree of collaboration.

When to use: When the state of an object (target object) changes, all dependent objects (observer objects) will be notified and broadcast notifications will be made.

How to solve: Using object-oriented technology, this dependency can be weakened.

Key code: There is an ArrayList in the abstract class to store observers.

Application examples: 1. During the auction, the auctioneer observes the highest bid and then notifies other bidders to bid. 2. In Journey to the West, Wukong asked the Bodhisattva to surrender the Red Boy. The Bodhisattva sprinkled water all over the ground and attracted an old turtle. This turtle was the observer. He observed the action of the Bodhisattva sprinkling water.

Advantages: 1. The observer and the observed are abstractly coupled. 2. Establish a trigger mechanism.

Disadvantages: 1. If an observed object has many direct and indirect observers, it will take a lot of time to notify all observers. 2. If there is a cyclic dependency between the observer and the observation target, the observation target will trigger cyclic calls between them, which may cause the system to crash. 3. The observer mode does not have a corresponding mechanism to allow the observer to know how the observed target object has changed, but only to know that the observation target has changed.

Usage scenarios: 1. There are methods common to multiple subclasses with the same logic. 2. Important and complex methods can be considered as template methods.

Notes: 1. JAVA already has support classes for the observer pattern. 2. Avoid circular references. 3. If executed sequentially, an observer error will cause the system to freeze, and an asynchronous method is generally used.

Implementation

The observer pattern uses three classes: Subject, Observer and Client. The Subject object has methods for binding observers to and unbinding observers from the Client object. We create the Subject class, the Observer abstract class, and the entity class that extends the abstract class Observer.

ObserverPatternDemo, our demo class uses Subject and entity class objects to demonstrate the observer pattern.

observer_pattern_uml_diagram.jpg

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 the entity observer class.

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 entity 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

Verify the output.

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