Behavioral Pattern - Observer Pattern

1 Overview

Definition: Also known as the publish-subscribe (Publish/Subscribe) pattern, it defines a one-to-many dependency relationship, allowing multiple observer objects to listen to a certain topic object at the same time. The subject object notifies all observer objects of state changes, enabling them to update themselves automatically.

2. Structure

In the observer mode, there are the following roles:

  • Subject: abstract subject (abstract observed), the abstract subject role saves all observer objects in a collection, each subject can have any number of observers, abstract subject provides an interface, you can add and delete observer objects .
  • ConcreteSubject: Specific subject (specific observer), this role stores the relevant state into the specific observer object, and sends a notification to all registered observers when the internal state of the specific subject changes.
  • Observer: Abstract observer is an abstract class of observer, which defines an update interface, so that it updates itself when it is notified of theme changes.
  • ConcrereObserver: Concrete observer, which implements the update interface defined by the abstract observer, so as to update its own state when it is notified of topic changes.

3. Case realization

[Example] WeChat official account

When using the WeChat official account, everyone will have such an experience. When there is a new content update in the official account you follow, it will be pushed to the WeChat client who follows the official account. We use the observer mode to simulate such a scenario, WeChat users are observers, WeChat public account
It is the observed person, and there are many WeChat users who have followed the official account of Program Ape.

The class diagram is as follows:

code show as below

package com.itheima.pattern.observer;

/**
 * @program: design-patterns
 * @interfaceName Subject
 * @description: abstract subject role
 * @author: 
 * @create: 2023-01-26 11:01
 * @Version 1.0
 **/
public interface Subject {
    // Add subscriber (add observer object)
    void attach(Observer observer);

    // delete subscriber
    void detach(Observer observer);

    // Notify subscribers of updated messages
    void notify(String message);
}
package com.itheima.pattern.observer;

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

/**
 * @program: design-patterns
 * @ClassName SubscriptionSubject
 * @description: Specific thematic roles
 * @author: 
 * @create: 2023-01-26 11:04
 * @Version 1.0
 **/
public class SubscriptionSubject implements Subject {

    // Define a collection to store multiple observer objects
    private List<Observer> weiXinUserList = new ArrayList<>();

    @Override
    public void attach(Observer observer) {
        weiXinUserList.add(observer);
    }

    @Override
    public void detach(Observer observer) {
        weiXinUserList.remove(observer);
    }

    @Override
    public void notify(String message) {
        // iterate through the collection
        for (Observer observer : weiXinUserList) {
            // Call the update method in the observer object
            observer.update(message);
        }
    }
}
package com.itheima.pattern.observer;

/**
 * @program: design-patterns
 * @interfaceName Observer
 * @description: abstract observer interface
 * @author: 
 * @create: 2023-01-26 11:01
 * @Version 1.0
 **/
public interface Observer {
    void update(String message);
}
package com.itheima.pattern.observer;

/**
 * @program: design-patterns
 * @ClassName WeiXinUser
 * @description: Concrete observer role class
 * @author: 
 * @create: 2023-01-26 11:07
 * @Version 1.0
 **/
public class WeiXinUser implements Observer {

    private String name;

    public WeiXinUser(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        System.out.println(name + "-" + message);
    }
}
package com.itheima.pattern.observer;

/**
 * @program: design-patterns
 * @ClassName Client
 * @description: test class
 * @author: 
 * @create: 2023-01-26 11:09
 * @Version 1.0
 **/
public class Client {
    public static void main(String[] args) {
        // 1. Create an official account object
        SubscriptionSubject subject = new SubscriptionSubject();
        // 2. Subscribe to official accounts
        subject.attach(new WeiXinUser("Sun Wukong"));
        subject.attach(new WeiXinUser("Zhu Bajie"));
        subject.attach(new WeiXinUser("Sha Wujing"));
        // 3. Update the official account and send a message to subscribers
        subject.notify("The column of Chuanzhi Podcast has been updated!");
    }
}

4. Advantages and disadvantages

  • advantage
    • The coupling relationship between the target and the observer is reduced, and there is an abstract coupling relationship between the two.
    • The observed person sends a notification, and all registered observers will receive the information [Broadcast mechanism can be realized]
  • shortcoming
    • If there are many observers, it will take time for all observers to receive notifications from the observed
    • If the observer has a circular dependency, the notification sent by the observer will cause the observer to call circularly, which will cause the system to crash

5. Usage scenarios

  • There is a one-to-many relationship between objects, and changes in the state of one object will affect other objects.
  • When an abstract model has two aspects, one of which depends on the other.

6. Implementation provided in JDK

In Java, the observer pattern is defined through the java.util.Observable class and the java.util.Observer interface, as long as their subclasses are implemented, observer pattern instances can be written.

6.1 Observable class

The Observable class is an abstract target class (observed). It has a Vector collection member variable for saving all observer objects to be notified. Let's introduce its three most important methods.

  • void addObserver(Observer o) method: used to add a new observer object to the collection.
  • void notifyObservers(Object arg) method: Call the update method of all observer objects in the collection to notify them of data changes. Usually observers who joined the set later will be notified earlier.
  • void setChange() method: used to set an internal flag of boolean type, indicating that the target object has changed. notifyObservers() will only notify observers when it is true.

6.2 Observer interface

The Observer interface is an abstract observer that monitors changes in the target object. When the target object changes, the observer is notified and calls the update method to perform corresponding work.

[Example]The police caught a thief

The observer pattern can also be used for the police to catch the thief. The police are the observers, and the thief is the observed. code show as below:
The thief is an observer, so it needs to inherit the Observable class

package com.itheima.pattern.observer.jdk;

import java.util.Observable;

/**
 * @program: design-patterns
 * @ClassName Thief
 * @description: Specific subject class
 * @author: 
 * @create: 2023-01-26 11:43
 * @Version 1.0
 **/
public class Thief extends Observable {
    private String name;

    public Thief(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void steal() {
        System.out.println("Thief: I stole something, is there anyone to catch me! ! !");
        super.setChanged(); //changed = true
        super.notifyObservers();
    }
}

The police is an observer, so it needs to implement the Observer interface

package com.itheima.pattern.observer.jdk;

import java.util.Observable;
import java.util.Observer;

/**
 * @program: design-patterns
 * @ClassName Policemen
 * @description: concrete observer class
 * @author: 
 * @create: 2023-01-26 11:45
 * @Version 1.0
 **/
public class Policemen implements Observer {

    private String name;

    public Policemen(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("Policemen:" + ((Thief) o).getName() + ",I've been watching you for a long time, you can keep silent, but what you say will be evidence in court! ! !");
    }
}

client code

package com.itheima.pattern.observer.jdk;

/**
 * @program: design-patterns
 * @ClassName Client
 * @description: test class
 * @author: 
 * @create: 2023-01-26 11:49
 * @Version 1.0
 **/
public class Client {
    public static void main(String[] args) {
        //Create a thief object
        Thief t = new Thief("Pharaoh next door");
        //create police object
        Policemen p = new Policemen("Xiao Li");
        //keep the police on the thief
        t.addObserver(p);
        //thief stealing
        t.steal();
    }
}

Tags: Design Pattern

Posted by ruiner17 on Fri, 27 Jan 2023 09:38:52 +0530