Good luck in the Year of the Rooster… !

The observer pattern is the behavior pattern of an object. It is also called Publish/Subscribe, Model/View, Source/Listener or Dependents.

The observer pattern defines a one-to-many dependency that allows multiple observer objects to listen on a subject object simultaneously. When the topic object changes in its state, all observer objects are notified so that they can update themselves automatically.

The observer model

A software system often requires that when information about one object changes, some other objects change accordingly. There are many designs to do this, but in order to make the system easy to reuse, a low coupling design should be chosen. Reducing the coupling between objects is beneficial to the reuse of the system, but at the same time, designers need to maintain the coordination of actions between these objects with low coupling degree to ensure a high degree of collaboration. Observer mode is one of the most important design schemes to meet this requirement. Let’s look at the structure of the observer mode:





  • Abstract Subject roles: Abstract Subject roles store all references to observer objects in an aggregate (such as an ArrayList object), and each Subject can have any number of observers. Abstract themes provide an interface to add and remove observer objects. Abstract theme roles are also called Abstract Observable roles.
  • ConcreteSubject Roles: Store the relevant state into a concrete observer object; All registered observers are notified when the internal status of a specific topic changes. Concrete subject role is also called Concrete Observable role.
  • Abstract Observer Role: Defines an interface for all concrete observers to update themselves when notified by a topic. This interface is called the update interface.
  • ConcreteObserver Role: The ConcreteObserver role that stores the state of the theme. The concrete observer role implements the update interface required by the abstract observer role to coordinate its own state with that of the topic. The specific observer role can maintain a reference to a specific subject object if desired. The observer model is divided into push model and pull model:
  • Push model topic objects push topic details to the observer, usually all or part of the topic object’s data, whether the observer needs it or not.
  • The pull model subject object conveys only a small amount of information when notifying the observer. If the observer needs more specific information, the observer actively goes to the topic object to get it, which is equivalent to the observer pulling data from the topic object. Typically, the implementation of this model passes the subject object itself to the observer via the update() method, so that the observer can retrieve data from this reference whenever it needs to. It might be confusing to just say that, but let’s have the code.

    Push model source code

    Abstract Subject class:

    public abstract class Subject {
      /** * Holds the registered observer object */
      private List<Observer> list = new ArrayList<Observer>();
      /** * Register observer * @param Observer */
      public void attach(Observer observer){
    
          list.add(observer);
          System.out.println("Attached an observer");
      }
      /** * Delete observer * @param observer */
      public void detach(Observer observer){
    
          list.remove(observer);
      }
      /** * Notifies all registered observer objects */
      public void nodifyObservers(String newState){
    
          for(Observer observer : list){ observer.update(newState); }}}Copy the code

    Specific Subject class:

    public class ConcreteSubject extends Subject {
    
      private String state;
    
      public String getState() {
          return state;
      }
    
      public void change(String newState){
          state = newState;
          System.out.println("Change the topic status to:" + state); // Notify observers of state changes. NodifyObservers (state); }}Copy the code

    Abstract Observer class:

    Public interface Observer {/** * Update interface * @paramstateUpdate status */ public void update(Stringstate);
    }Copy the code

    Specific observer:

    public class ConcreteObserver implements Observer {
      // The state of the observer
      private String observerState;
    
      @Override
      public void update(String state) {
          /** * Updates the observer's state to match the target's */
          observerState = state;
          System.out.println("State is:"+observerState); }}Copy the code

    The test class:

    public class Client {
      public static void main(String[] args) {
          // Create a theme object
          ConcreteSubject subject = new ConcreteSubject();
          // Create an observer object
          Observer observer = new ConcreteObserver();
          // Register the observer object with the subject object
          subject.attach(observer);
          // Change the state of the subject object
          subject.change("new state"); }}Copy the code

    Results:

    Attached AN Observer Changes the subject status to newstateThe state of the observer is: newstateCopy the code

    Pull model source code

    The difference with the push model is that the pull model usually passes the topic object as a parameter.

    public interface Observer {
      /** * update interface * @param subject passes in the subject object, the aspect gets the state of the corresponding subject object */
      public void update(Subject subject);
    }Copy the code

    Where the specific observer is implemented:

    @Override
      public void update(Subject subject) {
          /** * Updates the observer's state to match the target's */
          observerState = ((ConcreteSubject)subject).getState();
          System.out.println("The observer state is:"+observerState);
      }Copy the code

    Subject’s nodifyObservers(String newState) becomes:

    public void nodifyObservers(a){
    
          for(Observer observer : list){
              observer.update(this); }}Copy the code

    A comparison of the two models

  • The push model assumes that the subject object knows the data the observer needs; In the pull model, the subject object does not know what data the observer needs. If there is no way, it simply passes itself to the observer and lets the observer value the data as needed.
  • The push model can make the observer object difficult to reuse because the observer’s update() method is defined as needed and may not be able to accommodate usage cases that are not taken into account. This means that it is possible to provide a new update() method when a new situation arises, or simply re-implement the observer; This is not the case with the pull model, because the update() method takes the topic object itself, which is basically the largest set of data that the topic object can pass, and can be used in any situation.

    Android usage observer mode

    We may every day in the daily development of them in use is adapter. The notifyDataSetChanged () in the BaseAdapter:

    private final DataSetObservable mDataSetObservable = new DataSetObservable();
    public void registerDataSetObserver(DataSetObserver observer) {
          mDataSetObservable.registerObserver(observer);
      }
    
    public void unregisterDataSetObserver(DataSetObserver observer) {
          mDataSetObservable.unregisterObserver(observer);
      }
    public void notifyDataSetChanged(a) {
          mDataSetObservable.notifyChanged();
      }Copy the code

    The DataSetObservable is android. Database. Observables < DataSetObserver > subclass

    DataSetObservable extends Observable<DataSetObserver>Copy the code

    mDataSetObservable.notifyChanged(); Source:

    public void notifyChanged() {
          synchronized(mObservers) {
              // since onChanged() is implemented by the app, it could do anything, including
              // removing itself from {@link mObservers} - and that could cause problems if
              // an iterator is used on the ArrayList {@link mObservers}.
              // to avoid such problems, just march thru the list in the reverse order.
              for (int i = mObservers.size() - 1; i >= 0; i--) {
                  mObservers.get(i).onChanged(); }}}Copy the code

    How exactly to implement the logically inheritable DataSetObserver corresponding method. There is also, of course, the more commonly used event registration for view.setonClickListener (). The observer model is used in many ways. Then there’s EventBus and RxJava, the tripartite frameworks that we’ve touched on at least once, which are implemented based on the Observer pattern. RxJava is more widely used than EventBus, which is just a messaging tool, but can do almost anything in RxJava, although it may be a bit redundant for simple tasks. EventBus is relatively lightweight. A disadvantage of EventBus is that classes that use EventBus cannot be confused, otherwise Evnetbus will not find the OnEvent method.