banner
jzman

jzman

Coding、思考、自觉。
github

Observer Design Pattern

Recently, I have been studying design patterns related to the Observer pattern. I will be learning about the Observer pattern from the following aspects:

  1. What is the Observer design pattern?
  2. Understanding key concepts.
  3. Ways to notify observers.
  4. Implementation of the Observer pattern.
  5. Advantages and disadvantages of the Observer pattern.
  6. Use cases.

What is the Observer design pattern?#

The Observer pattern is a software design pattern that defines a one-to-many relationship between objects. When an object's data changes, it notifies other objects that depend on it, allowing them to respond to the data changes. This design pattern, which establishes a one-to-many notification relationship when the data of the target object changes, is called the Observer design pattern.

Understanding key concepts#

The Observer design pattern mainly distinguishes between two concepts:

  • Observer: Refers to the observer object, which is the subscriber of the message.
  • Subject: Refers to the target object to be observed, which is the publisher of the message.

Ways to notify observers#

When the subject's data changes, there are two main ways to notify the observers:

  • Push: The message is broadcasted to the observers, and the observers can only passively and unconditionally receive it.
  • Pull: The observer receives a notification from the subject and can independently decide to retrieve the message.

Implementation of the Observer pattern#

Below are two ways to implement the Observer design pattern:

  1. Implementing the Observer pattern manually:
    First, create the subject that observers will observe:
/**
 * The target object that observers want to observe.
 */
public abstract class Subject {
    protected ArrayList<Observer> observerList = new ArrayList<>();
    
    public void registerObserver(Observer obs) {
        observerList.add(obs);
    }
    
    public void unRegisterObserver(Observer obs) {
        observerList.remove(obs);
    }
    
    public void notifyAllObserver(){
        for (Observer observer : observerList) {
            observer.update(this);
        }
    }
}

Create the concrete subject:

/**
 * The concrete target object.
 */
public class ConcreteSubject extends Subject{
    private int state;
    
    public int getState() {
        return state;
    }
    
    public void setState(int state) {
        this.state = state;
        notifyAllObserver();
    }
}

Next, define the observer interface for convenience:

/**
 * Observer interface.
 */
public interface Observer {
    void update(Subject subject);
}

Create the concrete observer:

/**
 * The concrete observer.
 */
public class ConcreteObserver implements Observer{
    private int state;
    
    public int getState() {
        return state;
    }
    
    public void setState(int state) {
        this.state = state;
    }
    
    @Override
    public void update(Subject subject) {
        ConcreteSubject concreteSubject = (ConcreteSubject)subject;
        state = concreteSubject.getState();
    }
}

Finally, test the Observer pattern:

/**
 * Main class.
 */
public class Client {
    public static void main(String[] args) {
        ConcreteSubject concreteSubject = new ConcreteSubject();
        
        ConcreteObserver obs1 = new ConcreteObserver();
        ConcreteObserver obs2 = new ConcreteObserver();
        ConcreteObserver obs3 = new ConcreteObserver();
        
        concreteSubject.observerList.add(obs1);
        concreteSubject.observerList.add(obs2);
        concreteSubject.observerList.add(obs3);
        
        concreteSubject.setState(10);
        
        System.out.println("Observer obs1: " + obs1.getState());
        System.out.println("Observer obs2: " + obs2.getState());
        System.out.println("Observer obs3: " + obs3.getState());
    }
}

The expected output is:

Observer obs1: 10
Observer obs2: 10
Observer obs3: 10

By changing the data of the target object, the data of the corresponding observers is updated, achieving message subscription and sending.

  1. Using the Observer and Observable provided by the Java API:
    Create a class that extends Observable as the subject:
/**
 * The subject (target object).
 */
public class ConcreteSubject extends Observable{
    private int state;
    
    public int getState() {
        return state;
    }
    
    public void setState(int state) {
        this.state = state;
        setChanged();
        notifyObservers(state);
    }
}

Create a class that implements Observer as the observer:

/**
 * The observer.
 */
public class ConcreteObserver implements Observer{
    private int state;
    
    public int getState() {
        return state;
    }
    
    public void setState(int state) {
        this.state = state;
    }
    
    @Override
    public void update(Observable arg0, Object arg1) {
        ConcreteSubject concreteSubject = (ConcreteSubject) arg0;
        this.state = concreteSubject.getState();
    }
}

Finally, test the Observer pattern:

/**
 * Test the Observer pattern.
 */
public class Client {
    public static void main(String[] args) {
        ConcreteSubject concreteSubject = new ConcreteSubject();
        
        ConcreteObserver obs1 = new ConcreteObserver();
        ConcreteObserver obs2 = new ConcreteObserver();
        ConcreteObserver obs3 = new ConcreteObserver();
        
        concreteSubject.addObserver(obs1);
        concreteSubject.addObserver(obs2);
        concreteSubject.addObserver(obs3);
        
        concreteSubject.setState(100);
        
        System.out.println("Observer obs1: " + obs1.getState());
        System.out.println("Observer obs2: " + obs2.getState());
        System.out.println("Observer obs3: " + obs3.getState());
    }
}

The expected output is:

Observer obs1: 100
Observer obs2: 100
Observer obs3: 100

Advantages and disadvantages of the Observer pattern#

  • Advantages: The observer and subject are abstractly coupled, allowing for a stable message triggering mechanism.
  • Disadvantages: If the subject has multiple indirect observers, the message delivery will consume more time. If there is a circular dependency between the observer and subject, it may eventually lead to system crashes.

Use cases#

The Observer design pattern is widely used in development, mainly in the following scenarios:

  • In processes such as games and chats, where messages are forwarded from the server to the client.
  • The broadcast mechanism in Android and the notification of data changes in ListView also use the Observer design pattern.
  • Subscription-related systems, where subscribers are synchronized with updated topics.

This concludes the Observer design pattern.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.