Design pattern 3 - Observer Pattern

Observer mode: defines one to many dependencies between objects. When an object changes state, the objects that depend on it will receive notification and update automatically. In fact, it is the publish and subscribe mode. The publisher publishes information, the subscriber obtains information, and the subscriber can receive information after subscribing to it. Without subscription, the subscriber cannot receive information.

Observer mode application scenario

Spring's ApplicationEvent, Zk event notification node, message subscription notification, Android development event registration, nacos config configuration refresh of distributed configuration center, asynchronous event driven

Observer mode schematic class diagram

Abstract observer role: that is, an abstract topic, which saves all references to observer objects in a collection. Each topic can have any number of observers. Abstract topics provide an interface to add and remove observer roles. It is generally implemented with an abstract class and interface.

Abstract observer role: define an interface for all concrete observers to update themselves when notified of the topic.

Specific observer role: that is, a specific topic. When the internal status of the collective topic changes, all registered observers will send a notice.

Concrete observer role: implement the update interface required by the abstract observer role, while coordinating its own state with the state of the drawing.

 

Simple implementation of observer mode. Case 1:

Simulate the O & M platform to push the Alter exception warning to the O & M personnel

Abstract observer

public interface Observer {
    /**
     *Notify observer message
     * @param message
     */
    void sendMessage(String message);
}

Abstract subject

public abstract class BrianSubject {
    /**
     * Add observer
     * @param observer
     */
   public abstract void addObserver(Observer observer);

    /**
     * Remove observer
     * @param observer
     */
    public abstract void removeObserver(Observer observer);

    /**
     * Notification message
     * @param message
     */
    public abstract void notifyObserver(String message);
}


Specific topics

@Component
public class AlertSubject extends BrianSubject {

    private List<Observer> observerList ;

    private ExecutorService executorService;

    public AlertSubject() {
        this.observerList = new ArrayList<>();
        this.executorService = Executors.newFixedThreadPool(10);
    }

    @Override
    public void addObserver(Observer observer) {
        observerList.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observerList.remove(observer);
    }

    @Override
    public void notifyObserver(String message) {
        observerList.forEach(observer -> {
            executorService.execute(() -> observer.sendMessage(message));
        });
    }
}

Specific observer

@Component
@Slf4j
public class AlertEmailObserver implements Observer {

    /**
     *  Email notification O & M
     * @param message
     */
    @Override
    public void sendMessage(String message) {
        log.info("Notify the operation and maintenance personnel by email: {}",message);
    }
}

@Component
@Slf4j
public class AlertSlackObserver implements Observer {

    /**
     * Slack Notify O & M
     * @param message
     */
    @Override
    public void sendMessage(String message) {
        log.info("Slack Notify O & M personnel: {}",message);
    }
}

@Component
@Slf4j
public class AlertSmsObserver implements Observer {

    /**
     *  SMS notification O & M
     * @param message
     */
    @Override
    public void sendMessage(String message) {
        log.info("Notify the operation and maintenance personnel by SMS: {}",message);
    }
}

Run test

@RestController
public class TestObserverController {

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private AlertSubject alertSubject;


    /**
     *  Simulate the operation and maintenance platform to notify the operation and maintenance personnel
     * @param message
     * @return
     */
    @GetMapping("/testAlertMessage")
    public ResponseEntity<?> order(@RequestParam String message){
        alertSubject.notifyObserver(message);
        return new ResponseEntity<>("Message sent", HttpStatus.OK);

    }


    /**
     *  Simulate user booking notification
     * @return
     */
    @GetMapping("/order")
    public ResponseEntity<?> order(){
        Map<String, String> map = new HashMap<>();
        map.put("orderId","QW12345676545");
        map.put("content","2020-07-01 Munich -> Hong Kong KA800 flight");
        map.put("price","$1000");
        OrderMessageEvent orderMessageEvent = new OrderMessageEvent(this,map);
        applicationContext.publishEvent(orderMessageEvent);
        return new ResponseEntity<>(map, HttpStatus.OK);

    }
}

Implement notification based on Spring encapsulated event listening, case 2

Simulate the user to notify the user after ordering air tickets

Spring implements event notification, and the underlying layer is encapsulated in observer mode

// Define events, i.e. messages sent
public
class OrderMessageEvent extends ApplicationEvent { //Content of mass messages private Map map; public Map getMap() { return map; } public void setMap(Map map) { this.map = map; } public OrderMessageEvent(Object source, Map map) { super(source); this.map = map; } } // Define listening classes @Component public class EmailListener implements ApplicationListener<OrderMessageEvent> { @Override @Async public void onApplicationEvent(OrderMessageEvent orderMessageEvent) { System.out.println(Thread.currentThread().getName() + " Send mail message:" + orderMessageEvent.getMap().toString()); } } @Component public class SmsListener implements ApplicationListener<OrderMessageEvent> { @Override @Async public void onApplicationEvent(OrderMessageEvent orderMessageEvent) { System.out.println(Thread.currentThread().getName() + " Send SMS message:" + orderMessageEvent.getMap().toString()); } } @Component public class WechatListener implements ApplicationListener<OrderMessageEvent> { @Override @Async public void onApplicationEvent(OrderMessageEvent orderMessageEvent) { System.out.println(Thread.currentThread().getName() + " Send wechat notification message:" + orderMessageEvent.getMap().toString()); } }

// Publish message
 /**
     *  Simulate user booking notification
     * @return
     */
    @GetMapping("/order")
    public ResponseEntity<?> order(){
        Map<String, String> map = new HashMap<>();
        map.put("orderId","QW12345676545");
        map.put("content","2020-07-01 Munich -> Hong Kong KA800 flight");
        map.put("price","$1000");
        OrderMessageEvent orderMessageEvent = new OrderMessageEvent(this,map);
        applicationContext.publishEvent(orderMessageEvent);
        return new ResponseEntity<>(map, HttpStatus.OK);

    }


test result

Advantages of observer mode
1. To repeat the code, making the code clearer, easier to read and easier to expand
2. Decoupling makes the code more maintainable. When modifying the code, you can change as few places as possible
Using the observer mode can do these two things well. Add an observer, directly create a new observer and register it with the subject object. Delete the observer, and the subject object calls the method to delete it. Then it is OK, and the rest is irrelevant. When the state of the subject object changes, it will automatically notify each observer

Tags: Programming

Posted by Think Pink on Mon, 30 May 2022 17:46:41 +0530