Observer mode (behavioral)

The first step of observer mode learning: copying concepts

  • Definition: defines a one to many dependency between objects. When the state of an object changes, all objects that depend on it will be notified and updated automatically
  • It mainly solves the problem of notifying other objects of an object's state change, and needs to consider ease of use and low coupling to ensure a high degree of cooperation
  • When to use: when the state of an object (target object) changes, all dependent objects (observer object) will be notified and broadcast
  • How to solve: using object-oriented technology, this dependency can be weakened
  • Key code: there is an ArrayList in the abstract class to store all observers

Observer mode learning step 2: bring in the scene

  • 1. Auction: at the auction, everyone will pay attention to the highest bid price (target object) quoted by the auctioneer. After the highest bid price is changed, the auctioneer trumpets to inform all bidders (that is, the observers, whether to add money or not depends on themselves) - here it is added: the target object is the highest bid price, not the auctioneer, and the auctioneer is only a tool responsible for broadcasting
  • 2. Crossroads: there are traffic lights (target objects) at the crossroads. People on their legs, riding bicycles, driving cars and traffic police are all observers. When the left turn light is green, they turn left and go straight. The traffic police have to follow the light and stand at attention, turn left / right, and put their hands up for instructions...

Observer mode learning step 3: understanding programming 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
  • The change of one object will lead to the change of one or more other objects, and the coupling between objects can be reduced by not knowing how many objects will change
  • An object must notify other objects, and he does not know who these objects are
  • You need to create A trigger chain in the system. The behavior of object A will affect object B, and the behavior of object B will affect object C.. You can use the observer mode to create A chain trigger mechanism

Observer mode learning step 4: draw class diagram ☺☺☺

Observer mode learning step 5: story telling (code above) ☺☺☺☺☺☺

Background: thieves don't go to the short auction store and get an ancient dragon egg through their unique channels. Therefore, they have made a lot of advertisements and hope people from all walks of life to participate in the auction
Theme 1: the thief does not take the empty dragon egg advertisement
Topic 2: price of dragon egg

Observer 1: Lord of Wu soul Hall
Observer 2: leader of Haotian sect
Observer 3: head of the blue Tyrannosaurus Rex family
Observer 4: leader of Qibao Liuli sect

Topic and observer interface
/**
 * @author Thieves don't leave empty
 * @description Abstract theme (observed)
 * @since 2021/7/6 11:12 afternoon
 */
public interface Subject {
    /**
     * Add subscriber
     * @param observer
     */
    void attach(Observer observer);
    /**
     * Delete subscriber
     * @param observer
     */
    void detach(Observer observer);
    /**
     * Notify subscribers of update messages
     */
    void notify(String message);

}
/**
 * @author Thieves don't leave empty
 * @description Observer interface, which all observers need to implement
 * @since 2021/7/6 11:14 afternoon
 */
public interface Observer {
    /**
     * Update method
     */
    void update(String message);
}
Realization of advertising theme and dragon egg price theme
/**
 * @author Thieves don't leave empty
 * @description Dragon egg advertising theme
 * @since 2021/7/6 11:23 afternoon
 */
@Component
public class DragonEggAdvertisementSubject implements Subject {
    // Store all observers who pay attention to dragon egg ads
    private List<Observer> observers = new ArrayList<>();

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

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

    @Override
    public void notify(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}
/**
 * @author Thieves don't leave empty
 * @description Dragon egg advertising theme
 * @since 2021/7/6 11:23 afternoon
 */
@Component
public class DragonEggPriceSubject implements Subject {
    // Store all observers who pay attention to the price of dragon eggs
    private List<Observer> observers = new ArrayList<>();

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

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

    @Override
    public void notify(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}
Several big people (actual observers)
/**
 * @author Thieves don't leave empty
 * @description
 * @since 2021/7/6 11:27 afternoon
 */
@Component
public class Observer1 implements Observer {

    private final static String NAME = "Haotian sect leader";

    @Override
    public void update(String message) {
        JSONObject jsonObject = JSONObject.parseObject(message);
        // Which theme
        String subject = jsonObject.getString("subject");
        // content
        String body = jsonObject.getString("body");
        System.out.println(NAME+"I saw it"+subject+"The message is"+body);
        if ("Thieves don't go short shooting the advertising department of the store".equals(subject)) {
            System.out.println(NAME+"He said: this news is very important. Even if we can't get it, we must not let the Wulin hall get it");
            System.out.println();
        } else {
            System.out.println(NAME+"Say: 100000 soul coins");
        }
    }
}
/**
 * @author Thieves don't leave empty
 * @description
 * @since 2021/7/6 11:27 afternoon
 */
@Component
public class Observer2 implements Observer {

    private final static String NAME = "Lord of Wu soul Hall";

    @Override
    public void update(String message) {
        JSONObject jsonObject = JSONObject.parseObject(message);
        // Which theme
        String subject = jsonObject.getString("subject");
        // content
        String body = jsonObject.getString("body");
        System.out.println(NAME+"I saw it"+subject+"The message is"+body);
        if ("Thieves don't go short shooting the advertising department of the store".equals(subject)) {
            System.out.println(NAME+"Said: the dragon egg must be mine");
            System.out.println();
        } else {
            System.out.println(NAME+"Say: 110000 soul coins");
        }
    }
}
/**
 * @author Thieves don't leave empty
 * @description
 * @since 2021/7/6 11:27 afternoon
 */
@Component
public class Observer3 implements Observer {

    private final static String NAME = "Qibao Liuli sect";

    @Override
    public void update(String message) {
        JSONObject jsonObject = JSONObject.parseObject(message);
        // Which theme
        String subject = jsonObject.getString("subject");
        // content
        String body = jsonObject.getString("body");
        System.out.println(NAME+"I saw it"+subject+"The message is"+body);
        if ("Thieves don't go short shooting the advertising department of the store".equals(subject)) {
            System.out.println(NAME+"He said: the last three schools are still the first in terms of financial resources. We should stop the Wulin hall this time. Their ambition is really terrible");
            System.out.println(NAME+"He said: send me an order to gather all the assets that can be gathered within three days. We must get the dragon egg");
            System.out.println();
        } else {
            System.out.println(NAME+"Say: 120000 soul coins");
        }
    }
}
/**
 * @author Thieves don't leave empty
 * @description
 * @since 2021/7/6 11:27 afternoon
 */
@Component
public class Observer4 implements Observer {

    private final static String NAME = "Leader of the blue Tyrannosaurus Rex family";

    @Override
    public void update(String message) {
        JSONObject jsonObject = JSONObject.parseObject(message);
        // Which theme
        String subject = jsonObject.getString("subject");
        // content
        String body = jsonObject.getString("body");
        System.out.println(NAME+"I saw it"+subject+"The message is"+body);
        if ("Thieves don't go short shooting the advertising department of the store".equals(subject)) {
            System.out.println(NAME+"He said: if we get dragon eggs, our blue electric Tyrannosaurus Rex family will certainly be stronger. Even if we bet on the whole family this time, we must win it");
            System.out.println(NAME+"He said: I ordered that all the valuable assets in the family should be sold as much as possible within three days, and the dragon eggs must be taken after three days");
            System.out.println();
        } else {
            System.out.println(NAME+"Say: 130000 soul coins");
        }
    }
}
Test the feeling of having an auction
/**
 * @author Thieves don't leave empty
 * @description
 * @since 2021/7/7 2:24 afternoon
 */
@Component
public class ObserverMain {
    public static int price = 100000;

    public static void main(String[] args) throws InterruptedException {
        System.out.println("The thieves did not go to the short auction store and obtained an ancient dragon egg through their unique channels. Therefore, they made a lot of advertisements and hoped that people from all walks of life would come to participate in the auction");
        System.out.println();
        System.out.println();
        System.out.println();
        System.out.println();
        Thread.sleep(2000);
        // Create dragon egg advertising theme (observed)
        Subject dragonEggAdvertisement = new DragonEggAdvertisementSubject();
        Observer observer1 = new Observer1();
        Observer observer2 = new Observer2();
        Observer observer3 = new Observer3();
        Observer observer4 = new Observer4();
        dragonEggAdvertisement.attach(observer1);
        dragonEggAdvertisement.attach(observer2);
        dragonEggAdvertisement.attach(observer3);
        dragonEggAdvertisement.attach(observer4);
        Map<String,String> map = new HashMap<>();
        map.put("subject","Thieves don't go short shooting the advertising department of the store");
        map.put("body","Dragon eggs will be auctioned in three days");
        dragonEggAdvertisement.notify(JSONObject.toJSONString(map));
        Thread.sleep(3000);
        System.out.println("Three days later,The auction was held as scheduled...");
        Subject dragonEggPrice = new DragonEggPriceSubject();
        dragonEggPrice.attach(observer1);
        dragonEggPrice.attach(observer2);
        dragonEggPrice.attach(observer3);
        dragonEggPrice.attach(observer4);
        map.put("subject","Thief doesn't empty auction house technician 1");
        map.put("body",price+"");
        dragonEggPrice.notify(JSONObject.toJSONString(map));
        System.out.println("The dragon egg battle began");
    }
}
Look at the results of the execution
The thieves did not go to the short auction store and obtained an ancient dragon egg through their unique channels. Therefore, they made a lot of advertisements and hoped that people from all walks of life would come to participate in the auction

The leader of Haotian sect saw the news that the thief did not go short auction the advertising department of the store. The content was that the dragon eggs would be auctioned in three days
 The leader of Haotian sect said: this news is very important. Even if we can't get it, we must not let the Wulin hall get it

The owner of Wuhun hall saw the news that the thief did not go short to shoot the advertising department of the store. The content was that the dragon eggs would be auctioned in three days
 The Lord of Wu soul Hall said: the dragon egg must be mine

Qibao liulizong saw the news that the thief did not go short to shoot the advertising department of the store. The content was that the dragon eggs would be auctioned in three days
 Qibao Liuli sect said: the last three sects are still the first of our Qibao Liuli sect in terms of financial resources. They want to stop the Wulin hall this time. Their ambition is really terrible
 Qibao Liuli sect said: send me an order to gather all the assets that can be gathered within three days. We must get dragon eggs

The patriarch of the blue electric Tyrannosaurus Rex family saw the news that the thief did not go short auction the advertising department of the store, which said that the dragon eggs would be auctioned in three days
 The head of the blue Tyrannosaurus Rex family said: our blue Tyrannosaurus Rex family can be stronger if we get dragon eggs. Even if we bet on the whole family this time, we must win it
 The patriarch of the blue electric Tyrannosaurus Rex family said: pass my order that all valuable assets in the family should be sold as much as possible within three days, and the dragon eggs must be taken in three days

Three days later,The auction was held as scheduled...
The leader of Haotian sect saw the news that the thief didn't empty technician 1 of the auction house. The content was 100000
 The leader of Haotian sect said: 100000 soul coins
 The Lord of Wu soul hall saw the news that the thief did not empty technician 1 of the auction house. The content was 100000
 The Lord of Wu soul Hall said: 110000 soul coins
 Qibao liulizong saw the news that the thief did not empty the No. 1 technician of the auction house. The content was 100000
 Qibao Liuli sect said: 120000 soul coins
 The patriarch of the blue Tyrannosaurus Rex family saw the news that the thief did not empty technician 1 of the auction house. The content was 100000
 The patriarch of the blue electric Tyrannosaurus Rex family said: 130000 soul coins
 The dragon egg battle began

Step 6 of observer mode learning: Java has built-in observer mode. Let's try it ☺☺☺☺☺☺

First of all, there is no need to define the interface between the observed and the Observer. The observed inherits the Observable class, and the Observer can implement the Observer interface. See the code
Realization of advertising theme and dragon egg price theme
import java.util.Observable;

/**
 * @author Thieves don't leave empty
 * @description Dragon egg advertising theme
 * @since 2021/7/6 11:23 afternoon
 */
@Component
public class DragonEggAdvertisementSubject extends Observable {
    public void setMessage(Object o){
        this.setChanged();
        this.notifyObservers(o);
    }
}
import java.util.Observable;

/**
 * @author Thieves don't leave empty
 * @description Dragon egg advertising theme
 * @since 2021/7/6 11:23 afternoon
 */
@Component
public class DragonEggPriceSubject extends Observable {

    public void setMessage(Object o){
        this.setChanged();
        this.notifyObservers(o);
    }
}
Several big people (actual observers) each observer has a built-in method to register the observed
import java.util.Observable;
import java.util.Observer;

/**
 * @author Thieves don't leave empty
 * @description
 * @since 2021/7/6 11:27 afternoon
 */
@Component
public class Observer1 implements Observer {

    private final static String NAME = "Haotian sect leader";
    public void registerSubject(Observable observable)
    {
        observable.addObserver(this);
    }
    
    @Override
    public void update(Observable o, Object arg) {
        JSONObject jsonObject = JSONObject.parseObject(arg.toString());
        // Which theme
        String subject = jsonObject.getString("subject");
        // content
        String body = jsonObject.getString("body");
        System.out.println(NAME+"I saw it"+subject+"The message is"+body);
        if (o instanceof DragonEggAdvertisementSubject) {
            System.out.println(NAME+"He said: this news is very important. Even if we can't get it, we must not let the Wulin hall get it");
            System.out.println();
        }
        if (o instanceof DragonEggPriceSubject) {
            System.out.println(NAME+"Say: 100000 soul coins");
        }
    }
}
import java.util.Observable;
import java.util.Observer;

/**
 * @author Thieves don't leave empty
 * @description
 * @since 2021/7/6 11:27 afternoon
 */
@Component
public class Observer2 implements Observer {

    private final static String NAME = "Lord of Wu soul Hall";

    public void registerSubject(Observable observable)
    {
        observable.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {
        JSONObject jsonObject = JSONObject.parseObject(arg.toString());
        // Which theme
        String subject = jsonObject.getString("subject");
        // content
        String body = jsonObject.getString("body");
        System.out.println(NAME+"I saw it"+subject+"The message is"+body);
        if (o instanceof DragonEggAdvertisementSubject) {
            System.out.println(NAME+"Said: the dragon egg must be mine");
            System.out.println();
        }
        if (o instanceof DragonEggPriceSubject) {
            System.out.println(NAME+"Say: 110000 soul coins");
        }
    }
}

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

/**
 * @author Thieves don't leave empty
 * @description
 * @since 2021/7/6 11:27 afternoon
 */
@Component
public class Observer3 implements Observer {

    private final static String NAME = "Qibao Liuli sect";

    public void registerSubject(Observable observable)
    {
        observable.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {
        JSONObject jsonObject = JSONObject.parseObject(arg.toString());
        // Which theme
        String subject = jsonObject.getString("subject");
        // content
        String body = jsonObject.getString("body");
        System.out.println(NAME+"I saw it"+subject+"The message is"+body);
        if (o instanceof DragonEggAdvertisementSubject) {
            System.out.println(NAME+"He said: the last three schools are still the first in terms of financial resources. We should stop the Wulin hall this time. Their ambition is really terrible");
            System.out.println(NAME+"He said: send me an order to gather all the assets that can be gathered within three days. We must get the dragon egg");
            System.out.println();
        }
        if (o instanceof DragonEggPriceSubject) {
            System.out.println(NAME+"Say: 120000 soul coins");
        }
    }
}
import java.util.Observable;
import java.util.Observer;

/**
 * @author Thieves don't leave empty
 * @description
 * @since 2021/7/6 11:27 afternoon
 */
@Component
public class Observer4 implements Observer {

    private final static String NAME = "Leader of the blue Tyrannosaurus Rex family";

    public void registerSubject(Observable observable)
    {
        observable.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {
        JSONObject jsonObject = JSONObject.parseObject(arg.toString());
        // Which theme
        String subject = jsonObject.getString("subject");
        // content
        String body = jsonObject.getString("body");
        System.out.println(NAME+"I saw it"+subject+"The message is"+body);
        if (o instanceof DragonEggAdvertisementSubject) {
            System.out.println(NAME+"He said: if we get dragon eggs, our blue electric Tyrannosaurus Rex family will certainly be stronger. Even if we bet on the whole family this time, we must win it");
            System.out.println(NAME+"He said: I ordered that all the valuable assets in the family should be sold as much as possible within three days, and the dragon eggs must be taken after three days");
            System.out.println();
        }
        if (o instanceof DragonEggPriceSubject) {
            System.out.println(NAME+"Say: 130000 soul coins");
        }
    }
}
There are also some relative changes in the code executed
The main change is that instead of directly adding corresponding observers to the topic, the topic can register itself (the topic can also choose not to register)
/**
 * @author Thieves don't leave empty
 * @description
 * @since 2021/7/7 2:24 afternoon
 */
@Component
public class ObserverMain {
    public static int price = 100000;

    public static void main(String[] args) throws InterruptedException {
        System.out.println("The thieves did not go to the short auction store and obtained an ancient dragon egg through their unique channels. Therefore, they made a lot of advertisements and hoped that people from all walks of life would come to participate in the auction");
        System.out.println();
        Thread.sleep(2000);
        // Create dragon egg advertising theme (observed)
        DragonEggAdvertisementSubject dragonEggAdvertisement = new DragonEggAdvertisementSubject();
        Observer1 observer1 = new Observer1();
        Observer2 observer2 = new Observer2();
        Observer3 observer3 = new Observer3();
        Observer4 observer4 = new Observer4();
        observer1.registerSubject(dragonEggAdvertisement);
        observer2.registerSubject(dragonEggAdvertisement);
        observer3.registerSubject(dragonEggAdvertisement);
        observer4.registerSubject(dragonEggAdvertisement);
        Map<String,String> map = new HashMap<>();
        map.put("subject","Thieves don't go short shooting the advertising department of the store");
        map.put("body","Dragon eggs will be auctioned in three days");
        dragonEggAdvertisement.setMessage(JSONObject.toJSONString(map));
        Thread.sleep(3000);
        System.out.println("Three days later,The auction was held as scheduled...");
        DragonEggPriceSubject dragonEggPrice = new DragonEggPriceSubject();
        observer1.registerSubject(dragonEggPrice);
        observer2.registerSubject(dragonEggPrice);
        observer3.registerSubject(dragonEggPrice);
        observer4.registerSubject(dragonEggPrice);
        map.put("subject","Thief doesn't empty auction house technician 1");
        map.put("body",price+"");
        dragonEggPrice.setMessage(JSONObject.toJSONString(map));
        System.out.println("The dragon egg battle began");
    }
}
The final execution result is also consistent with that before
The thieves did not go to the short auction store and obtained an ancient dragon egg through their unique channels. Therefore, they made a lot of advertisements and hoped that people from all walks of life would come to participate in the auction

The patriarch of the blue electric Tyrannosaurus Rex family saw the news that the thief did not go short auction the advertising department of the store, which said that the dragon eggs would be auctioned in three days
 The head of the blue Tyrannosaurus Rex family said: our blue Tyrannosaurus Rex family can be stronger if we get dragon eggs. Even if we bet on the whole family this time, we must win it
 The patriarch of the blue electric Tyrannosaurus Rex family said: pass my order that all valuable assets in the family should be sold as much as possible within three days, and the dragon eggs must be taken in three days

Qibao liulizong saw the news that the thief did not go short to shoot the advertising department of the store. The content was that the dragon eggs would be auctioned in three days
 Qibao Liuli sect said: the last three sects are still the first of our Qibao Liuli sect in terms of financial resources. They want to stop the Wulin hall this time. Their ambition is really terrible
 Qibao Liuli sect said: send me an order to gather all the assets that can be gathered within three days. We must get dragon eggs

The owner of Wuhun hall saw the news that the thief did not go short to shoot the advertising department of the store. The content was that the dragon eggs would be auctioned in three days
 The Lord of Wu soul Hall said: the dragon egg must be mine

The leader of Haotian sect saw the news that the thief did not go short auction the advertising department of the store. The content was that the dragon eggs would be auctioned in three days
 The leader of Haotian sect said: this news is very important. Even if we can't get it, we must not let the Wulin hall get it

Three days later,The auction was held as scheduled...
The patriarch of the blue Tyrannosaurus Rex family saw the news that the thief did not empty technician 1 of the auction house. The content was 100000
 The patriarch of the blue electric Tyrannosaurus Rex family said: 130000 soul coins
 Qibao liulizong saw the news that the thief did not empty the No. 1 technician of the auction house. The content was 100000
 Qibao Liuli sect said: 120000 soul coins
 The Lord of Wu soul hall saw the news that the thief did not empty technician 1 of the auction house. The content was 100000
 The Lord of Wu soul Hall said: 110000 soul coins
 The leader of Haotian sect saw the news that the thief didn't empty technician 1 of the auction house. The content was 100000
 The leader of Haotian sect said: 100000 soul coins
 The dragon egg battle began

It can be seen that using the jdk can make our code more concise. Here, by the way, post the source code of the two functions called by the observer, otherwise there may be some questions

  • setChanged()
protected synchronized void setChanged() {
        changed = true;
    }
  • notifyObservers(Object arg)
public void notifyObservers(Object arg) {
        Object[] arrLocal;
        synchronized (this) {
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }
        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }

You can see that it's just a very simple operation. Execute clearChanged() after there are changes

protected synchronized void clearChanged() {
        changed = false;
    }
OK, that's all the code

Step 6: summarize the advantages and disadvantages of observer mode

advantage

  • The observer and the observed are abstractly coupled, which makes the classes that must be related flexible enough
  • Observer mode establishes a trigger broadcast mechanism

shortcoming

  • If there are many observers to be observed, it is time-consuming to inform them all
  • In the actual development scenario, the observer and the observer object are likely to rely on each other circularly
  • The observer only knows that the observed person has changed, but he doesn't know why

extend

The practical application of observer model can be divided into two models

  • Push model: the observer pushes the change details to the observer. No matter whether the observer needs it or not, the pushed information is usually all or all of the change data of the observed object.
  • Pull model: when the observed object notifies the observer, it only transmits a small amount of information. If the observer needs more specific information, the observer takes the initiative to obtain it from the observed object, which is equivalent to the observer pulling data from the observed object.
    Note: the pull model is generally used. The specific implementation needs to pass the observed object itself to the observer through the update() method, so that when the observer needs to obtain data, it can be obtained through this reference.

If you are interested, you can look at your own code implementation. Different mode choices are also processed according to the actual scene

Keywords: Java Design Pattern

Added by chanfuterboy on Thu, 20 Jan 2022 06:50:07 +0200