During development, we often encounter the requirement that if the state of an object A changes, some of its related objects should also change accordingly. In general, object A needs to be able to access these objects in order to call update methods, but this is an undesirable way to create coupling. For low coupling, the observer pattern can be used.

define

The Observer pattern, one of the behavioral patterns, defines a one-to-many dependency that allows multiple Observer objects to listen on a subject object at the same time. The topic object notifies all observer objects when it changes its state, enabling them to update themselves automatically. A topic object can correspond to multiple observers that are not previously related to each other, and observers can be added and removed as needed, making the system easier to expand.

structure

  • Subject: Abstract Subject. Abstract topic roles store all observer objects in a collection, each topic can have any number of observers, and abstract topics provide an interface to add and remove observer objects.
  • ConcreteSubject: Concrete theme. This role stores the relevant state to a specific observer object and notifies all subscribed observers when the internal state of a specific topic changes.
  • Observer: Abstract Observer, an abstract class for the Observer that defines an update interface to update itself when notified of a topic change.
  • ConcrereObserver: A concrete observer that implements an update interface defined by an abstract observer to update its own state when notified of a topic change.

Simple implementation

  • Abstract Topic class
    abstract class Subject {
        private Vector obs = new Vector();


        public void addObserver(Observer obs){
            this.obs.add(obs);
        }
        public void delObserver(Observer obs){
            this.obs.remove(obs);
        }
        protected void notifyObserver() {for(Observer o: obs){
                o.update();
            }
        }
        public abstract void doSomething();
    }Copy the code
  • Specific subject class
    class ConcreteSubject extends Subject {
        public void doSomething(){
            System.out.println("Observed event generated in reverse."); this.notifyObserver(); }}Copy the code
  • Abstract observer
    interface Observer {
        public void update();
    }Copy the code
  • Concrete observer
    class ConcreteObserver1 implements Observer {
        public void update() {
            System.out.println("Observer 1 receives the message and processes it.");
        }
    }
    class ConcreteObserver2 implements Observer {
        public void update() {
            System.out.println("Observer 2 receives the message and processes it."); }}Copy the code
  • use
public class Client { public static void main(String[] args){ Subject sub = new ConcreteSubject(); sub.addObserver(new ConcreteObserver1()); // addObserver 1 sub.addobserver (new ConcreteObserver2()); // Add observer 2 sub.dosomething (); }}Copy the code

Running results:

The observed event is generated in reverse
Observer 1 receives the message and processes it.
Observer 2 receives the message and processes it.

The instance

NSNotificationCenter and NSNotification

Notification mechanism in iOS is a very typical observer mode. All classes can listen and send NSNotification through NSNotificationCenter. The observer and the observed do not need to know each other. You just need to find the class in the NSNotificationCenter that is listening for the notification through the tag (such as NotificationName) and call the methods of that class. Also, in NSNotificationCenter, observers can subscribe to and respond to a particular notification instead of updating all notifications sent by a class. The NSNotificationCenter calls to the observer are not random, but are executed one by one in the order of registration, and are synchronous within the thread.

@property (class, readonly, strong) NSNotificationCenter *defaultCenter;


- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSNotificationName)aName object:(nullable id)anObject;


- (void)postNotification:(NSNotification *)notification;
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject;
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;


- (void)removeObserver:(id)observer;
- (void)removeObserver:(id)observer name:(nullable NSNotificationName)aName object:(nullable id)anObjecCopy the code

The advantages and disadvantages

advantages

1. Decouple so that both sides of the coupling depend on abstraction so that neither transformation affects the transformation on the other side.

2. The observer mode complies with the “on/Off principle”. If a new observer needs to be introduced, there is no need to modify the observed object

disadvantages

1. If an observation object has many direct and indirect observers, notifying all observers takes a lot of time and increases the complexity of development and debugging

2. If there is a cyclic dependency between the observer and the observed target, circular calls may be made, resulting in system crash

Contrast with other design patterns

Chain of Responsibility model

The observer pattern can also split the notification chain, much like the chain of responsibility pattern

1. In the chain of responsibility mode, each recipient contains a reference to another recipient, while in the observer mode, the observed does not know who the observer is

2. In pure chain of responsibility mode, only one receiver will process the request, while observer mode allows each observer to process

Command mode

1. The command mode is one-to-one and the observer mode is one-to-many

2. Command mode sends commands for the recipient to execute. In observer mode, the sending class (observed) doesn’t care what happens to the receiving class (observer)

The mediator pattern

The mediator pattern establishes a bidirectional connection between the components of the mediator pattern, while the observer pattern is unidirectional between the observed and the observer.

One of the reasons it is difficult to distinguish the observer pattern from the mediator pattern is that a popular implementation of the mediator pattern relies on the observer pattern. Mediation objects play the role of publishers, and components act as observers, subscribing to and unsubscribing to mediation events. When implemented this way, the mediator pattern can look very similar to the observer pattern. However, the mediator pattern can be implemented in other ways. For example, all components can be permanently linked to the same mediation object. This implementation is not like the observer pattern, but it is still the mediator pattern.