The observer model is quite useful in business development. It is quite simple in itself. After understanding it, I immediately optimized the current project.

Observer model#

The observer pattern describes a one-to-many relationship, where one can be a state change or an event. For example, in view of the order of payment, after the creation of the incident may need through a number of processing steps, such as integration, warehousing, operation consumption list, these operations can even there is no connection between the parallel processing, so can be understood as the payment and order a one-to-many relationship between processing steps. Another feature is one-way dependence, processing steps for order payment is one-way dependence, such as order payment, can have processing steps. But on the contrary, it does not depend on the order payment is not concerned about the processing steps, which will be explained in detail in the actual combat below.

Observer pattern structure#

The main structure of observer mode is as follows:

  • Subject: A role that is responsible for notifying specific observers of events that are generated. The notification is actually a circular call to the observer interface that it holds
  • Observer: is responsible for the processing of events. This interface can achieve a good separation of tasks. Each different task is a subclass of its implementation and does not care about each other, which describes the business relationship well.

So what is the essence? Using a Subject to aggregate all the observers, the caller only needs to care about the corresponding Subject. Why is that possible? Since observers have no relationship to each other, they simply do what they do, and do not need to return values or anything like that.

A case study in the observer mode#

As described by the author at the beginning, some processing steps should be carried out after the payment of the order is completed, as follows:

  1. If it is a virtual goods order, issue the virtual goods
  2. If it is a member order, then open membership
  3. Points are added based on the amount paid
  4. Update the amount of money if there is a leaderboard activity.
  5. … .

This is a common post-payment operational requirement in development, and it is easy to add other processing step requirements as activities and so on increase. For the observer pattern, it conforms to the following two characteristics:

  1. Order payment completes this event in a pair of processing steps, typical of a one-to-many relationship
  2. There is no correlation between the processing steps, each is an independent processing

Observer mode design#

The above observation mode can be used to design the following structure:

OrderPaidHandlerObserver It is the interface that the observer needs to implement. Its main function is to determine whether it can handle itself, and if it can handle itself, it will handle. Its subclasses have their own roles, for example, IntegralOrderService is to handle integral-related observers, and VipOrderService is to handle members-related services.

Public interface OrderPaidHandlerObserver {/** * Whether processing the message is supported * @param paidMsg message body * @return true Supported */ Boolean supportHandler(OrderPaidMsgDTO paidMsg); /** @param paidMsg message body */ void handler(OrderPaidMsgDTO paidMsg); }Copy the code

OrderPaidHandlerSubject is the interface responsible for notifying all observers. Implementing this interface has the obligation to notify observers.

Public interface OrderPaidHandlerSubject {/** * notifyObservers @param paidMsg Payment messages */ void notifyObservers(OrderPaidMsgDTO paidMsg); }Copy the code

OrderCompositeService It is the implementation class of OrderPaidHandlerSubject, which mainly implements the logic responsible for notifying all observers. Notification is essentially calling its own observer object, so when the order payment event is generated, OrderCompositeService only needs to call notifyObse The rvers() method completes the notification, completing all the processing steps.

public class OrderCompositeService implements OrderPaidHandlerSubject { private List<OrderPaidHandlerObserver> observers; @override public void notifyObservers(OrderPaidMsgDTO paidMsg) {// The notification is essentially a call to the corresponding observer method for (OrderPaidHandlerObserver) observer : observers) { try { if (observer.supportHandler(paidMsg)) { observer.handler(paidMsg); } } catch (Exception e) { log.error("OrderPaidHandlerObserver fail", e); }}}... }Copy the code

Use Spring to manage observers#

OrderCompositeService, as a Subject, holds all of the observers, so if all of the observers are injected into the class using IOC, then the next time a new Observer implementation class is added there is no need to change any code here, complete decoupling. The idea is to manage all observers with IOC, get them when the Spring container is complete, and add them to the corresponding set, with OrderCompositeService implementing ApplicationListener

interface, which Spring notifies when it has started, initialses the desired collection of observers using BeanFactoryUtils.

*/ @override public void onApplicationEvent(ContextRefreshedEvent event) {initPaidObserver(event);  } private void initPaidObserver(ContextRefreshedEvent event) {// Fetch all observer Map<String,  OrderPaidHandlerObserver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(event.getApplicationContext(),  OrderPaidHandlerObserver.class, true, false); Set this. / / instantiate the observer observers = Collections. UnmodifiableList (Lists. NewArrayList (matchingBeans. The values ())); if (this.observers.size() <= 0) { throw new IllegalStateException("OrderPaidHandlerObserver not found"); } else { log.info("initPaidObserver finish, observer is {}", matchingBeans.keySet()); }}Copy the code

The advantage of this is to decouple the instantiation of the observer from the Subject, and it is sufficient for the observer to know that once it implements the observer interface, it must be notified by the corresponding Subject.

The granularity of the observer’s “interest.#

In Observer mode, the Observer registers itself with the Subject. What happens when the Subject corresponds to multiple events? 1.Subject Manages multiple groups of Observers Multiple groups of Observers are stored in A Subject. When an event is triggered, only one group is notified. This approach personally feels more reasonable. The disadvantage is that the management is not convenient, for Subject to manage multiple groups, the corresponding removeOvserver or addObserver will be more troublesome, in this case, you can rely on IOC and other tools to complete the process In this scheme, he only manages a group of observers for a Subject, but the observers themselves have to assume multiple responsibilities, and the responsibilities they are not interested in should be left blank. An Observer may be interested in only one thing but have to implement a bunch of empty methods that do not comply with the least know principle. Java’s AWT is designed in this way The JDK’s own Observer is a similar form, which uses Object as an Observer parameter. When receiving a message, it needs to use instance to determine whether it is the event that it is interested in, and then execute the logic. When there are few events, this method is more appropriate, but if there are many events, it is still troublesome to process a bunch of events separately. Eclipse’s SWT is designed this way.

reference#

Granularity control of observer mode “interest”

  • Copyright: All rights reserved by Qu Ding’s Blog. If reprinted, please indicate the source.
  • Article title: Design Patterns: Reflections on the Observer Model
  • Article link: mrdear.cn/2018/04/20/…

Spring MVC– Parameter parsing and method execution
Spring MVC– Parsing of return values