intentions

Defines a one-to-many dependency between objects so that when an object’s state changes, all dependent objects are notified and automatically updated

Aliases: publish – subscribe pattern

The birth of the observer model

A common side effect of splitting a system into a series of collaborating classes is that you need to maintain interoperability between related objects, and you don’t want to keep classes tightly coupled in order to maintain consistency, which reduces their reusability.

In human language:

[Product] : Developer, I need you to design a big screen for displaying weather forecast. The weather station will send you data. You need to display it on the big screen, OK?

Development: OJBK! Everything in seconds! Code out immediately!

void getTemperature (a) {
    // Get the temperature data sent from the weather station
    // getData();
    
    
 / /...  // Display it in the big screen  // showDataToScreen();  / /... }  void getMisture (a) {  // Get the humidity data sent from the weather station  // getData();    / /...  // Display it in the big screen  // showDataToScreen();  / /... }  void getAirindex (a) {  // Obtain the air index data from the weather station  // getData();    / /...  // Display it in the big screen  // showDataToScreen();  / /... } Copy the code

【BOSS】 : Knock big head! Do you want to CV the code every time you get the data? Aren’t you tired?

[Development] : Boss, I am not tired at all! Copy and paste it!

What if I don’t need to synchronize the weather index right now? Delete code?

[Development] : Right! It can be deleted in a second! (•̀ ω •́)✧

[BOSS] : Rewrite 😃

HeadFirst core code

And so we began our journey of reading classic books about design patterns

/ * ** Observe the topic interface* /
public interface Observable{
    public void addObserver(Observer observer);     // Add an observer
 public void removeObserver(Observer observer); // Remove the observer  public void notifyObservers(WeatherData data); // Notify all observers }   / * ** observer* / public interface Observer {  public abstract void update(WeatherData data); }   / * ** Weather Theme * * / public class Weather implements Observable {  private List<Observer> observers = new ArrayList<>();   public void addObserver(Observer observer) {  observers.add(observer);  }   public void removeObserver(Observer observer) {  observers.remove(observer);  }   public void notifyObservers(WeatherData data) {  for (Observer observer : observers)  observer.update(data);  } }  Copy the code

The design idea of observer mode:

  • The Subject target (container) provides interfaces for registering and deleting observers, as well as updating interfaces
  • Observer defines an update interface for objects that need to be notified when the target changes
  • Notifyobservers of ConcreteSubject changes in state
  • ConcreteObserver Implements the update interface for the Observer

In short,

  1. We need an interface to define the registration, deletion, and update interfaces
  2. The specific target (class) then implements the interface and creates a container within the class to store the objects that need to be notified
  3. Objects that need to be notified need to implement the Update method in the Observer interface
  4. The observer object is registered into the container, and the update method on all container-class objects is called when the target is updated

If that seems a bit ambiguous, after reading this article, visit the Thematic Design Patterns Open source project, which has specific code examples linked at the bottom

The Observer pattern in the JDK

There is already a concrete implementation of the Observer pattern in the JDK. The code is very simple, like this:

Specific objectives:

public class ObservableApp extends Observable {

    private long curr;
    
    public ObservableApp(long curr) {
 this.curr = curr;  }   public void change(long newStr) {  this.curr = newStr;   // Change the status and send a notification  setChanged();  notifyObservers(newStr);  }   @Override  protected synchronized void setChanged(a) {  super.setChanged();  } } Copy the code

Specific observer:

public class ObserverA implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println(MessageFormat.format("ObserverA -> {0} changed, Begin to Work. agr is:{1}", o.getClass().getSimpleName(), arg));
    }
} Copy the code

The Main method:

public class App {
    
    public static void main(String[] args) throws InterruptedException {
        ObservableApp app = new ObservableApp(System.currentTimeMillis());
        System.out.println(app.getCurr());
 app.addObserver(new ObserverA());  app.addObserver(new ObserverB());   Thread.sleep(1000);   long curr = System.currentTimeMillis();  app.change(curr);  System.out.println(app.getCurr());  } }  // Output is as follows: / / 1589688733464 // ObserverB -> ObservableApp changed, Begin to work.agr is:1,589,688,734,469 // ObserverA -> ObservableApp changed, Begin to work.agr is:1,589,688,734,469 / / 1589688734469 Copy the code

Push mode

Notices are distributed to observers, with parameters included in them, and are obsered in the JDK method: notifyObservers(Object ARg)

Pull mode

The notification is sent to the observer. The notification takes no parameters, and the observer needs to proactively call the GET method to get the data. This is called pull

Corresponding to the JDK method, notifyObservers(), only inform observers that the data has changed, and details of the data require the observer to proactively pull the data into the subject

The pull model emphasizes that the target does not know its observer, while the push model assumes that the target knows some information that the observer needs. The push model may make it relatively difficult for the observer to reuse because the target’s assumptions about the observer may not always be correct. On the other hand. The pull model can be inefficient because the observer object needs to determine what has changed without the help of the target object.

Follow the design principles

  1. Packaging changes
    • What often changes in the observer pattern is the state of the topic, as well as the number and type of observers
    • We can change objects that depend on the state of the topic, but we don’t have to change the topic itself, which is planning ahead
  2. Programming to an interface
    • Interfaces are used by both the subject and the observer
    • Observers register with a topic using the topic’s interface
    • The topic uses the observer interface to inform the observer, which enables the normal interaction between the two, but also has the characteristics of loose coupling
  3. Multi-use combination
    • The observer pattern uses composition to group many observers into a topic
    • The relationship between them is not inherited, but changes dynamically at run time

What scenarios are suitable for use

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

Code/ Practical application in life

  • For example, wechat public account subscription attention, subscription, the public number published articles will be distributed to each account in real time
  • For example, when we run with Keep, if you run hard enough, it will tell you, congratulations, you have broken the record for the best 5km! Such a voice reminder must be triggered, rather than real-time detection? (Real-time detection is meaningless, wasting performance.) This is where the observer pattern can be used for design and decoupling

The last

Attach the UML diagram for the observer pattern from GOF:

Observer pattern UML diagram

Related code links

Making the address

  • Examples from two classic data books, HeadFirst and GOF
  • Provides friendly reading instructions