"Design Patterns" Observer Pattern

"Design Patterns" Observer Pattern

Definition :

  • The observer mode, also known as the publish-subscribe mode , defines a one-to- many dependency relationship, and a subject object can be observed (monitored) by multiple observer objects at the same time. When the state of the subject object changes, all observer objects can be notified and automatically updated .
  • The core of the observer mode is to decouple the observer from the observed , and associate the two in a way similar to publish-subscribe, so that the status update of the observed can be notified to the observers who are interested in it.

The compositional roles of the observer pattern :

  • Subject (Subject) : also known as abstract notifier, generally implemented by an interface or abstract class. It holds a collection of references to all observer objects, defines methods for adding and removing any observer objects, and methods for notifying all observer objects.
  • ConcreteSubject : Also known as a specific notifier, when the state (data) changes, it sends a notification to all observers.
  • Abstract observer (Observer) : generally implemented by an abstract class or an interface, defines an interface for all specific observers, updates itself when notified by the subject, and usually contains update()methods
  • Concrete Observer (ConcreteObserver) : implement the update interface of the abstract observer, and at the same time maintain a reference to the specific subject object in the concrete observer, store the relevant state of the specific observer, and these states need to be consistent with the state of the specific subject object.

UML class diagram of the observer pattern :

insert image description here

Take a very simple application scenario case: simulate a news official account, users can subscribe and unsubscribe the official account at will, and when the news official account has news releases, all users who have subscribed to the official account will be notified. At any time, all subscribers receive the same news updates.

Abstract subject Subject :

public interface Subject {
    
    
    /**
     * 增加观察者对象
     * @param observer
     */
    void attach(Observer observer);

    /**
     * 删除观察者对象
     * @param observer
     */
    void detach(Observer observer);
    /**
     * 通知所有观察者对象
     */
    void notifyObserver();
}

Specific subject ConcreteSubject :

public class ConcreteSubject implements Subject{
    
    
    private List<Observer> observers = new ArrayList<>();
    private String subjectState;

    public String getSubjectState() {
    
    
        return subjectState;
    }

    public void setSubjectState(String subjectState) {
    
    
        this.subjectState = subjectState;
    }

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

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

    @Override
    public void notifyObserver() {
    
    
        for (Observer observer : observers) {
    
    
            observer.update();
        }
    }
}

Abstract Observer Observer :

public interface Observer {
    
    
    /**
     * 更新观察者的状态
     */
    void update();
}

Concrete observer ConcreteObserver :

public class ConcreteObserver implements Observer{
    
    
    private String name;
    private String observerState;
    private ConcreteSubject subject;

    public ConcreteObserver(String name, ConcreteSubject subject) {
    
    
        this.name = name;
        this.subject = subject;
    }

    @Override
    public void update() {
    
    
        observerState = subject.getSubjectState();
        System.out.println(String.format("观察者%s收到的消息是:%s", name, observerState));
    }
}

Client Client :

public class Client {
    
    
    public static void main(String[] args) {
    
    
        ConcreteSubject concreteSubject = new ConcreteSubject();
        concreteSubject.attach(new ConcreteObserver("node1", concreteSubject));
        concreteSubject.attach(new ConcreteObserver("node2", concreteSubject));
        concreteSubject.attach(new ConcreteObserver("node3", concreteSubject));
        concreteSubject.setSubjectState("Hello, observers!");
        concreteSubject.notifyObserver();
    }
}

Output result :

观察者node1收到的消息是:Hello, observers!
观察者node2收到的消息是:Hello, observers!
观察者node3收到的消息是:Hello, observers!

In fact, the JDK source code provides a skeleton for quickly using the observer mode java.util, Observerthe interface (equivalent to an abstract notifier) ​​and Observableclass (equivalent to an observer object) under the package.

Observer 接口

/**
*  抽象通知者
*/
public interface Observer {
    
    
    void update(Observable o, Object arg);
}

Observer 类

public class Observable {
    
    
    private boolean changed = false;
    private Vector<Observer> obs;
    public Observable() {
    
    
        obs = new Vector<>();
    }
    public synchronized void addObserver(Observer o) {
    
    
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
    
    
            obs.addElement(o);
        }
    }

    public synchronized void deleteObserver(Observer o) {
    
    
        obs.removeElement(o);
    }
 
    public void notifyObservers() {
    
    
        notifyObservers(null);
    }

    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);
    }
    
    public synchronized void deleteObservers() {
    
    
        obs.removeAllElements();
    }
    
    protected synchronized void setChanged() {
    
    
        changed = true;
    }
   
    protected synchronized void clearChanged() {
    
    
        changed = false;
    }
   
    public synchronized boolean hasChanged() {
    
    
        return changed;
    }
    
    public synchronized int countObservers() {
    
    
        return obs.size();
    }
}

The Observer interface and the Observable class UML class diagram are shown below :

insert image description here

Advantages of the observer pattern :

  • Establish an abstract coupling between the observation target and the observer . The observation target only needs to maintain a collection of abstract observers without knowing its specific observers, so that each change will not affect the change of the other side, which is in line with dependency inversion in principle.
  • Broadcast communication is supported . Observation targets will send notifications to all registered observer objects, simplifying the difficulty of one-to-many system design.
  • It satisfies the requirements of the open-close principle, adding new specific observers does not need to modify the original system code . It is also convenient to add a new observation target when there is no correlation between the specific observer and the observation target.

Disadvantages of observer pattern :

  • If an observation target object has many direct and indirect observers, it will take a lot of time to notify all observers.
  • If there is a circular dependency between the observer and the observed target, the observed target will trigger a cyclic call between them, possibly crashing the system.
  • There is no corresponding mechanism for the observer to know how the observed target object has changed, but only to know that the observed target has changed.

Application scenarios of observer mode :

  • An abstract model has two aspects, one of which depends on the other. At this time, the observer pattern can be used to encapsulate the two in independent objects so that they can be changed and reused independently.
  • A change to one object will cause one or more other objects to change, and it is not known exactly how many objects will change or who those objects are.
  • Need to create a trigger chain in the system, the behavior of the A object will affect the B object, the behavior of the B object will affect the C object... You can use the observer pattern to create a chain trigger mechanism.

Guess you like

Origin blog.csdn.net/weixin_43252521/article/details/129929855