设计模式3 - 观察者模式 Observer Pattern

Posted hlkawa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式3 - 观察者模式 Observer Pattern相关的知识,希望对你有一定的参考价值。

观察者模式:在对象之间定义了一对多的依赖,当一个对象改变状态,依赖它的对象会收到通知并自动更新。其实就是发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息。

观察者模式应用场景

Spring的ApplicationEvent、Zk事件通知节点、消息订阅通知、安卓开发事件注册、分布式配置中心nacos config配置刷新、异步事件驱动

观察者模式原理类图

技术图片

抽象被观察者角色:也就是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。

抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题通知时更新自己。

具体被观察者角色:也就是一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知。

具体观察者角色:实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。

 

观察者模式简单的实现,案例一:

模拟运维平台给运维人员推送Alter 异常警告

抽象观察者

public interface Observer {
    /**
     *通知观察者消息
     * @param message
     */
    void sendMessage(String message);
}

抽象主题者

public abstract class BrianSubject {
    /**
     * 添加观察者
     * @param observer
     */
   public abstract void addObserver(Observer observer);

    /**
     * 移除观察者
     * @param observer
     */
    public abstract void removeObserver(Observer observer);

    /**
     * 通知消息
     * @param message
     */
    public abstract void notifyObserver(String message);
}


具体主题
 

@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));
        });
    }
}

具体观察者

@Component
@Slf4j
public class AlertEmailObserver implements Observer {

    /**
     *  邮件通知运维
     * @param message
     */
    @Override
    public void sendMessage(String message) {
        log.info("邮件通知运维人员: {}",message);
    }
}

@Component
@Slf4j
public class AlertSlackObserver implements Observer {

    /**
     * Slack 通知运维
     * @param message
     */
    @Override
    public void sendMessage(String message) {
        log.info("Slack通知运维人员: {}",message);
    }
}

@Component
@Slf4j
public class AlertSmsObserver implements Observer {

    /**
     *  短信通知运维
     * @param message
     */
    @Override
    public void sendMessage(String message) {
        log.info("短信通知运维人员: {}",message);
    }
}

运行测试

@RestController
public class TestObserverController {

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private AlertSubject alertSubject;


    /**
     *  模拟运维平台 通知运维人员
     * @param message
     * @return
     */
    @GetMapping("/testAlertMessage")
    public ResponseEntity<?> order(@RequestParam String message){
        alertSubject.notifyObserver(message);
        return new ResponseEntity<>("消息已经发出", HttpStatus.OK);

    }


    /**
     *  模拟用户订票通知用户
     * @return
     */
    @GetMapping("/order")
    public ResponseEntity<?> order(){
        Map<String, String> map = new HashMap<>();
        map.put("orderId","QW12345676545");
        map.put("content","2020-07-01 慕尼黑 -> 香港 KA800 航班");
        map.put("price","$1000");
        OrderMessageEvent orderMessageEvent = new OrderMessageEvent(this,map);
        applicationContext.publishEvent(orderMessageEvent);
        return new ResponseEntity<>(map, HttpStatus.OK);

    }
}

技术图片

基于Spring封装事件监听实现通知,案例二

模拟用户订购机票后通知用户

Spring实现事件通知,底层采用观察者模式封装的

// 定义事件,即发送的消息
public
class OrderMessageEvent extends ApplicationEvent { //群发消息的内容 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; } } // 定义监听类 @Component public class EmailListener implements ApplicationListener<OrderMessageEvent> { @Override @Async public void onApplicationEvent(OrderMessageEvent orderMessageEvent) { System.out.println(Thread.currentThread().getName() + " 发送邮件消息:" + orderMessageEvent.getMap().toString()); } } @Component public class SmsListener implements ApplicationListener<OrderMessageEvent> { @Override @Async public void onApplicationEvent(OrderMessageEvent orderMessageEvent) { System.out.println(Thread.currentThread().getName() + " 发送短信消息:" + orderMessageEvent.getMap().toString()); } } @Component public class WechatListener implements ApplicationListener<OrderMessageEvent> { @Override @Async public void onApplicationEvent(OrderMessageEvent orderMessageEvent) { System.out.println(Thread.currentThread().getName() + " 发送微信通知消息:" + orderMessageEvent.getMap().toString()); } }

// 发布消息
 /**
     *  模拟用户订票通知用户
     * @return
     */
    @GetMapping("/order")
    public ResponseEntity<?> order(){
        Map<String, String> map = new HashMap<>();
        map.put("orderId","QW12345676545");
        map.put("content","2020-07-01 慕尼黑 -> 香港 KA800 航班");
        map.put("price","$1000");
        OrderMessageEvent orderMessageEvent = new OrderMessageEvent(this,map);
        applicationContext.publishEvent(orderMessageEvent);
        return new ResponseEntity<>(map, HttpStatus.OK);

    }


测试结果

技术图片

观察者模式的优点
1、去重复代码,使得代码更清晰、更易读、更易扩展
2、解耦,使得代码可维护性更好,修改代码的时候可以尽量少改地方
使用观察者模式可以很好地做到这两点。增加观察者,直接new出观察者并注册到主题对象之后就完事了,删除观察者,主题对象调用方法删除下就OK了,其余都不用管。主题对象状态改变,内部会自动帮我们通知每一个观察者.

以上是关于设计模式3 - 观察者模式 Observer Pattern的主要内容,如果未能解决你的问题,请参考以下文章

观察者模式Observer

观察者模式Observer

设计模式3 - 观察者模式 Observer Pattern

观察者模式(Observer)

Java中使用Observer接口和Observable类实践Observer观察者模式

观察者模式-Observer