Design mode --- observer mode

Article catalog


Observer pattern is mainly used to deal with one to many relationships among objects, which is an object behavior pattern. The actual application scenario of this mode is relatively easy to confirm. When an object's state changes, all the followers of the object can receive the state change notice for corresponding processing.
This paper hopes that through a simple introduction and analysis, readers can have a simple and intuitive understanding and perception of the observer model, so that it can be used flexibly in the actual development.

1. Purpose

Establish one to many relationship between objects, and make the change of an object be perceived by all related objects.

2. Motivation

Establish a set of low coupling message triggering mechanism.

3. Advantages and disadvantages

advantage:

There is abstract coupling between the observed and the observer;
The coupling degree is low, and the relationship between them is only the notification of messages;
The observed need not care about his observer;
Support broadcast communication;
Disadvantages:

The observer only knows that the observed object has changed, but does not know the process and reason of the change;
The observer may also be the observed, the link of message delivery may be too long, and it takes more time to complete all notifications;
If there is circular dependence between the observer and the observed, or the message transmission link forms a closed loop, it will lead to infinite loops;

4. Application scenario

It is necessary to establish a triggering mechanism of single broadcast in the system;
The behavior of one object in the system will affect several other objects;
The association between objects can be established and revoked dynamically at runtime;
The relationship between objects presents a tree structure;

5. Principle

The following is the UML class diagram of the typical class observer pattern introduced by GoF:

Subject:

Abstracts the observed, providing only interface declarations for registering and deleting observer objects.

ConcreteSubject:

The specific observed object, which collects all the observers that need to be notified, and can dynamically add and delete the observers in the set. All observer objects are notified when their state changes.

Observer:

Abstract observer, which defines a unified interface for all observers to receive notifications;

ConcreteObserver:

The observer object, whose focus object is Subject, can accept the notification when Subject changes and update its status.

6. Implementation

Next, convert the above UML class diagram into specific code, and then take a specific example to see its application.

Abstract observed class: Subject

public interface Subject {
    public void setState(int state);
    public int getState();
    public void attach(Observer obs);
    public void detach(Observer obs);
    public void notify(String msg);
}

Abstract Observer class: observer

public interface Observer {
    public void update(String msg);
}

Concrete observed class: ConcreteSubject
Create a list to store observers

public class ConcreteSubject implements Subject {
    
    private List<Observer> observerList = new ArrayList<Observer>();
    private int state;

    @Override
    public void setState(int state) {
        this.state = state;        
        notify("new state: " + state);
    }

    @Override
    public int getState() {
        // TODO Auto-generated method stub
        return 0;
    }
    
    @Override
    public void attach(Observer obs) {
        // TODO Auto-generated method stub
        observerList.add(obs);
    }

    @Override
    public void detach(Observer obs) {
        // TODO Auto-generated method stub
        observerList.remove(obs);
    }

    @Override
    public void notify(String msg) {
        // TODO Auto-generated method stub
        for (Observer obs: observerList) {
            obs.update(msg);
        }
    }
}

Specific Observer class: ConcreteObserver

public class ConcreteObserver implements Observer {

    @Override
    public void update(String msg) {
        // TODO Auto-generated method stub
        System.out.println("ConcreteObserver receive notify msg: " + msg);
    }

}

demonstration:

public class Demo {
    public static void main(String[] args) {
        ConcreteObserver obs = new ConcreteObserver();
        ConcreteSubject sub = new ConcreteSubject();
        sub.attach(obs);
        sub.setState(666);
        sub.notify("just test subject notify function!");
    }
}

result:

ConcreteObserver receive notify msg: new state: 666
ConcreteObserver receive notify msg: just test subject notify function!

7. Examples

Let's take a more practical example - the change of commodity price to realize the purpose of observer model.

When shopping online, there is usually a price change notice for the goods, provided that we pay attention to the goods.

Here we have a little flexibility. Only when the price of the concerned goods drops and is lower than the expected purchase price, will we send a message notice of the price reduction to the user.

Each class is defined as follows:

Product abstract class: product

public interface Product {
    public void setPrice(int price);
    public int getPrice();
    public void follow(User user);
    public void unfollow(User user);
    public void notifyLowPrice();
}

User abstract class: user

public interface User {
    public boolean isExpectedPrice(int price);
    public void shortMSG(String msg);
}

Laptop: laptop

public class Laptop implements Product {
    
    private List<User> followList = new ArrayList<User>();
    private int curPrice;

    @Override
    public void setPrice(int price) {
        curPrice = price;
        System.out.println("set laptop price: " + price);
        notifyLowPrice();
    }

    @Override
    public int getPrice() {
        return curPrice;
    }
    
    @Override
    public void follow(User user) {
        followList.add(user);
    }

    @Override
    public void unfollow(User user) {
        followList.remove(user);
    }

    @Override
    public void notifyLowPrice() {
        String msg = "" + curPrice;
        for (User user: followList) {
            if (user.isExpectedPrice(curPrice)) {
                user.shortMSG(msg);
            }
        }
    }
}

Focus on laptop users: LaptopBuyer

public class LaptopBuyer implements User {
    private int expectedPrice;
    private String userName;
    public LaptopBuyer(String userName, int expectedPrice) {
        this.userName = userName;
        this.expectedPrice = expectedPrice;
    }

    @Override
    public boolean isExpectedPrice(int curPrice) {
        // TODO Auto-generated method stub
        return curPrice <= expectedPrice;
    }

    @Override
    public void shortMSG(String msg) {
        // TODO Auto-generated method stub
        System.out.println("Your follow product have a low price: " + msg + " TO:" + userName);
    }

}

demonstration:

public class Demo {
    public static void main(String[] args) {
        LaptopBuyer Alice = new LaptopBuyer("Alice", 6000);
        LaptopBuyer Jack = new LaptopBuyer("Jack", 6500);
        Laptop laptop = new Laptop();
        laptop.follow(Alice);
        laptop.follow(Jack);
        laptop.setPrice(7000);
        laptop.setPrice(6500);
        laptop.setPrice(6000);
        laptop.unfollow(Jack);
        laptop.setPrice(5999);
        laptop.setPrice(6099);
    }
}

result:

set laptop price: 7000
set laptop price: 6500
Your follow product have a low price: 6500 TO:Jack
set laptop price: 6000
Your follow product have a low price: 6000 TO:Alice
Your follow product have a low price: 6000 TO:Jack
set laptop price: 5999
Your follow product have a low price: 5999 TO:Alice
set laptop price: 6099

The above example is a practical use of the observer pattern.

8. Summary

Compared with the observer mode, we may have many ways to obtain the state of another object, such as the common polling mode, or just check the state of the other party when necessary. However, the observer mode has its special purpose and is more flexible.

The principle of this mode is simple and direct, but some details need to be considered in the actual use process:

When to notify?
Who triggered the notification?
Does the observer focus on the number of state changes or the final state?
What if the message notification is blocked?
Can I change to asynchronous message notification?
All of the above should be considered in actual use. Only by considering these details can we apply the model more flexibly to solve practical problems.

Reprint

Reprint statement:
By alpha_panda
Address: https://www.cnblogs.com/yssjun/p/11107038.html

Posted on Sat, 13 Jun 2020 22:54:33 -0400 by kayess2004