1. Basic introduction

Description:

The observer pattern, also known as the Publish/Subscribe pattern, belongs to the object behavior pattern. It defines a one-to-many dependency between objects, allowing multiple observer objects to listen to a topic object at the same time. When the state of the topic object changes, all its observers are notified and updated automatically. A topic is the publisher of a notification and does not need to know who its observers are when it sends a notification. Any number of observers can subscribe and receive the notification.

Usage Scenarios:

  • An abstract model has two aspects, one of which depends on the other. Encapsulate these aspects in separate objects so that they can be changed and reused independently.
  • A change in one object will cause one or more other objects to change, and not knowing exactly how many objects will change can reduce the coupling between objects.
  • One object must notify other objects without knowing who they are, that is, they are not expected to be tightly coupled.

Application examples:

  • As soon as a Subject publishes a newspaper, it immediately sends it to all observers, who then have access to its contents.
  • The USER interface acts as an observer. Service data is observed. The user interface observes changes in service data and displays the changes on the user interface.

Core class description:

  • Subject: Abstract topics, i.e. objects being observed, maintain a collection of observers themselves.
  • Observer: Abstract Observer that responds to changes in the state of a topic and maintains a reference to the topic itself.

Matters needing attention:

  • Java already has classes that support the observer pattern.
  • Avoid circular references.
  • An observer error can cause the system to jam if executed sequentially, usually asynchronously.

2. Implement observer mode yourself

2.1 Design class diagram

Description:

  1. Subject interface: Defines the Subject interface that an object uses to register as an observer or remove itself from the observer. All entity classes that implement this interface are concrete Subject classes.
  2. Observer interface: Defines the Observer interface. All potential observers must implement the Observer interface. This interface has only one method, update(), which is called when the topic state changes.
  3. NewspaperOffice entity class: newspaperOffice class, realizing the subject interface, is the object to be observed. In addition to realizing the methods in the subject interface, the specific newspaper class also provides the methods of obtaining news information and setting news information. The newspaper class setting holds a list of its observers, using a string type to store news information for simplicity.
  4. Eric entity class: The user Eric, which implements the Observer interface, is the Observer object and holds references to the subject object.
  5. Shealtiel entity class: User Shealtiel, which implements the Observer interface as an Observer object and holds references to subject objects.
  6. Other concrete observed object classes that implement the Subject interface, and other Observer classes that implement the Observer interface.

2.2 Implementation Code

(1) Subject Interface

public interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObserver(a);
}
Copy the code

(2) Observer interface

public interface Observer {
    void update(String news);
}
Copy the code

(3) NewspaperOffice, realizing Subject interface, is the specific object to be observed.

public class NewspaperOffice implements Subject {
    private List<Observer> observers;  // List of newspaper observers
    private String news = "";          // The news of the newspaper

    public NewspaperOffice(a) {
        observers = new ArrayList<>(); // Initialize the observer list to an empty table
    }

    @Override
    public void registerObserver(Observer o) {
        if (o == null) {
            throw new NullPointerException();
        }
        if (!observers.contains(o)) {
            observers.add(o);
        }
    }

    @Override
    public void removeObserver(Observer o) {
        observers.remove(o);
    }

    @Override
    public void notifyObserver(a) {
        for(Observer observer : observers){
            observer.update(news);  // Update observer information}}public void setNews(String news) {
        this.news = news;
        notifyObserver();  // Notify the observer after setting the new message}}Copy the code

(4) Eric user class, implement the Observer interface, subscribe to the newspaper, for the Observer.

public class Eric implements Observer {
    private Subject subject;  // References to observed topics
    private String news;

    public Eric(Subject subject){
        this.subject = subject;
        this.subject.registerObserver(this); // Register this object as an observer for a specific topic
    }

    @Override
    public void update(String news) {
        this.news = news;
        showNews(); // Display the latest information after updating information
    }

    public void showNews(a){
        System.out.println("Eric: "+news);
    }

    public void unsubscribe(a){
        subject.removeObserver(this); }}Copy the code

(5) Shealtiel user class, implement the Observer interface, subscribe to the newspaper, for the Observer.

public class Shealtiel implements Observer {
    private Subject subject;  // References to observed topics
    private String news;

    public Shealtiel(Subject subject){
        this.subject = subject;
        this.subject.registerObserver(this); // Register this object as an observer for a specific topic
    }

    @Override
    public void update(String news) {
        this.news = news;
        showNews(); // Display the latest information after updating information
    }
    
    public void showNews(a){
        System.out.println("Shealtiel: "+news);
    }

    public void unsubscribe(a){
        subject.removeObserver(this); }}Copy the code

(6) Test classes

public class Demo {
    public static void main(String[] args) {
        // Instantiate the newspaper class (observed). The newspaper class implements the Subject interface, which is the concrete Subject class
        NewspaperOffice newspaperOffice = new NewspaperOffice();
        
        // Instantiate the user and subscribe to the newspaper information, which is initialized as an observer of the newspaper topic
        Eric eric = new Eric(newspaperOffice);
        Shealtiel shealtiel = new Shealtiel(newspaperOffice);

        // If the newspaper updates the information, the system will automatically notify the corresponding observer
        System.out.println("The newspaper updates the first message, noting the message received by the observer:");
        newspaperOffice.setNews("This is the first news!");
        
        System.out.println("\n Newspaper updates the second message, noting the message received by observers:");
        newspaperOffice.setNews("This is the second news!");

        // The Eric object unsubscribes to the newspaper, and Eric will not be notified of any news since it is no longer an observer of the newspaper
        System.out.println("\nEric unsubscribe news information");
        eric.unsubscribe();
        
        System.out.println("The newspaper updates the third message, noting the number of observers at this time:");
        newspaperOffice.setNews("This is the third news!"); }}Copy the code

(7) Test results

3. Java’s built-in Observer mode

1. Design the class diagram

Description:

  1. Observable class: Java built-in Observable class. All entity classes that extend this class are subject classes.
  2. Observer interface: Java’s built-in Observer interface. All observers must implement the Observer interface. This interface has only one method, *update()*, which is called when the topic state changes.

Note that one is a class and one is an interface.

Java’s built-in observer mode works similarly to our own code, but with a few minor differences. The most obvious difference is that NewspaperOffice (our subject) now extends from the Observable class and inherits methods for adding, deleting, notifying observers (among other things).

  • How do I turn an object into an observer?

As before, implement the Observer interface (java.uitl.observer) and call the addObserver() method of any Observable subject object. When you no longer want to be an observer, you simply call the deleteObserver() method.

  • How does the observed send notifications?

First, you need to extend the java.util.Observable class with inheritance to generate a concrete “observed” topic class. Then, there are two steps:

  1. The *setChanged()* method is first called to mark the fact that the state has changed;
  2. Then call bothnotifyObservers()One of the methods:
NotifyObservers () or notifyObservers (Object arg)Copy the code
  • How do observers receive notifications?

As before, the observer implements the newer method, but the method signature is different:

update(Observable o, Object arg)
Copy the code

If you want to “push” data to observers, you can send it as a data object to notifyObservers(ARG). Otherwise, the observer must “pull” the data from the observable.

  • See what the *setChanged()* method does.
// pseudo-code:
setChanged() {
	changed = true // Set the change state to true
}

// Only notify the observer if the changed value is true
notifyObservers(Object arg) {
	if (changed) {
		for every observer on the list {
			call update (this, arg)
		}
		changed = false
	}
}

notifyObservers() {
	notifyObservers(null)}Copy the code

2. Implemented using Java built-in observer pattern

(1) NewspaperOffice class, which inherits and extends Java built-in Observable class, is the observed object.

public class NewspaperOffice extends Observable {
    private String news; // The news of the newspaper

    // Note the difference with your own implementation, adding observers to the superclass to handle
    public NewspaperOffice(a) {}

    public void setNews(String news) {
        this.news = news;
        newsChanged();
    }

    public String getNews(a) {
        return news;
    }
    
    // Notify the observer when the content changes
    public void newsChanged(a) { setChanged(); notifyObservers(); }}Copy the code

(2) Eric user class, implement Java built-in Observer interface, subscription newspaper newspaper, for the Observer.

public class Eric implements Observer {
    private Observable observable;  // A reference to a topic
    private String news;
    
    public Eric(Observable observable){
        this.observable = observable;
        this.observable.addObserver(this); // Add this object as an observer
    }

    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof NewspaperOffice) {
            NewspaperOffice newspaperOffice = (NewspaperOffice) o;
            this.news = newspaperOffice.getNews();
            showNews(); // Display information after updating information}}public void showNews(a){
        System.out.println("Eric: "+news); }}Copy the code

(3) Shealtiel user class, implementation of Java built-in Observer interface, subscription newspaper newspaper, for the Observer.

public class Shealtiel implements Observer {
    private Observable observable; // A reference to a topic
    private String news;

    public Shealtiel(Observable observable){
        this.observable = observable;
        this.observable.addObserver(this); // Add this object as an observer
    }

    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof NewspaperOffice) {
            NewspaperOffice newspaperOffice = (NewspaperOffice) o;
            this.news = newspaperOffice.getNews();
            showNews(); // Display information after updating information}}public void showNews(a){
        System.out.println("Shealtiel: "+news); }}Copy the code

(4) Test classes

public class Demo {
    public static void main(String[] args) {
        // Instantiate the newspaper class (observed)
        NewspaperOffice newspaperOffice = new NewspaperOffice();
        // Instantiate the subscriber class (observer)
        Eric eric = new Eric(newspaperOffice);
        Shealtiel shealtiel = new Shealtiel(newspaperOffice);

        // The newspaper updates the information, and the corresponding observers will be notified automatically
        System.out.println("The newspaper updates the first message, noting the message received by the observer:");
        newspaperOffice.setNews("This is the first news!");
        System.out.println("\n Newspaper updates the second message, noting the message received by observers:");
        newspaperOffice.setNews("This is the second news!");

        // Eric objects unsubscribe from the newspaper and Eric will not be notified of subsequent news
        System.out.println("\nEric unsubscribe news information");
        newspaperOffice.deleteObserver(eric);

        System.out.println("The newspaper updates the third message, noting the number of observers at this time:");
        newspaperOffice.setNews("This is the third news!"); }}Copy the code

(5) Test results

3. Another implementation

The newspaper class:

public class NewsOffice extends Observable {
    // The newspaper is designed as a singleton.
    private static NewsOffice instance = new NewsOffice();

    private NewsOffice(a) {}

    public static NewsOffice getInstance(a) {
        return instance;
    }

    // News content
    private String news;

    public void setNews(String news) {
        this.news = news;
        updateNews();
    }

    private void updateNews(a) {
        System.out.println("The newspaper updated the news... News item:" + news);
        // Set changes to notify observers
        this.setChanged();
        this.notifyObservers(news); }}Copy the code

Two user classes:

public class Eric implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("Eric observed:" + o.getClass().getName());
        System.out.println("News received:"+ arg.toString()); }}public class Jack implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("Jack observed:" + o.getClass().getName());
        System.out.println("News received:"+ arg.toString()); }}Copy the code

The test class:

public class Test {
    public static void main(String[] args) {
        NewsOffice newsOffice = NewsOffice.getInstance();
        Eric user1 = new Eric();
        Jack user2 = new Jack();
        newsOffice.addObserver(user1);
        newsOffice.addObserver(user2);
        newsOffice.setNews("Mid-Autumn Festival is only two days away!!"); }}Copy the code

4. Another instance of e-commerce observing the product list

  1. First you define the observed class, which needs to be inheritedObservable classCall the parent class in the corresponding changed methodsetChanged()notifyObservers()Method to notify the appropriate observers and enable them to automatically make changes.
  2. Then you need to define the observer, you need to implementObserver interfaceAnd implementupdate()Method used to change and call the observed objectnotifyObservers()Automatically executes the observer update logic after the.
  3. To test, you create the observed and its instance objects, which then call the Observable classaddObserver()Method to add the corresponding instance object as its observer. Any subsequent changes to the observed object will be automatically notified and automatically updated to the observer.

Product List class (observed object) :

public class ProductList extends Observable {
    // Use hungry singleton mode
    private static ProductList instance = new ProductList();

    private ProductList(a) {}

    public static ProductList getInstance(a) {
        return instance;
    }

    private List<String> productList = new ArrayList<>();  // Product list
    
    // Add new products to the list of products, and the appropriate observers will be notified
    public void addProduct(String newProduct) {
        this.productList.add(newProduct);
        System.out.println("A new product has been added to the list of products named:" + newProduct);
        // Call the parent method to set the observed state to change
        this.setChanged();
        // Call the method of the parent class to notify all observers of the change and pass the changed object
        this.notifyObservers(newProduct); }}Copy the code

Jd E-commerce category (Observer) :

public class JingDongObserver implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("Jingdong e-commerce observation objects:" + o.getClass().getName());
        String newProduct = (String) arg;
        System.out.println(newProduct + "Synchronized to JINGdong e-commerce"); }}Copy the code

Taobao E-commerce category (Observer) :

public class TaoBaoObserver implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("Taobao e-commerce observation objects are:" + o.getClass().getName());
        String newProduct = (String) arg;
        System.out.println(newProduct + "Synchronized to Taobao e-commerce"); }}Copy the code

Testing:

public class ObserverTest {
    public static void main(String[] args) {
        // Create an instance of the product list to be observed
        ProductList productList = ProductList.getInstance();
        // Create an e-commerce instance of the watch product list as an observer
        JingDongObserver jdObserver = new JingDongObserver();
        TaoBaoObserver taoBaoObserver = new TaoBaoObserver();
        // Add the above two e-commerce objects as observers to the product list
        productList.addObserver(jdObserver);
        productList.addObserver(taoBaoObserver);
        // Use the addProduct method to add a new product to the product list
        // The corresponding superclass method is called in the addProduct method to notify the observer of the change, and the update method in the observer is automatically executed
        productList.addProduct("Product 1"); }}Copy the code

5. To summarize

5.1 the advantages

  • The observer and the observed are abstractly coupled, making both sides of the coupling dependent on the abstraction rather than the concrete.
  • Decouple the object, completely isolating the observer from the observed.
  • Use composite relationships between objects for more flexibility.

5.2 disadvantages

  • If an observed object has many direct and indirect observers, notifying all observers can take a long time.
  • If there is a cyclic dependency between the observer and the observed topic, the observed topic triggers a cyclic call between them, possibly causing the system to crash.
  • The observer mode only lets the observer know that the observed subject object has changed, but there is no corresponding mechanism to let the observer know exactly how the observed target subject object has changed.

5.3 Implement observer mode thinking by yourself

Firstly, two interfaces are designed, one is Subject interface and the other is Observer interface.

The concrete topic class then implements the Subject interface, and the concrete Observer class implements the Observer interface.

When an observer object is registered as an observer of a topic object, it can receive notifications published by that topic object.

5.4 Using the Java built-in Observer mode idea

Instead of designing its own interface, it uses Java’s built-in Observable class and Observer interface.

The concrete Observable class (the topic class) extends the Observable class, and the concrete Observer class implements the Observer interface.

When an observer object is registered as an observer of a topic object, it can receive notifications published by that topic object.

Note: The use of interface can be unified standard, and more flexible; Use composition more than inheritance.

Write in the last

Hi, I’m CoderGeshu, a programmer who loves life. If this article helps you, please give it a thumbs up at 👍.

In addition, welcome to pay attention to my namesake public account: CoderGeshu, a dedicated to sharing programming technology knowledge of the public account, must have you want ~~