zoukankan      html  css  js  c++  java
  • 设计模式3

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

    观察者模式应用场景

    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了,其余都不用管。主题对象状态改变,内部会自动帮我们通知每一个观察者.

  • 相关阅读:
    IaaS、PaaS、SaaS
    hyper-V 配置
    解决linux下创建用户时出现Creating mailbox file: File exists
    iframe层级关系调用
    js,jq新增元素 ,on绑定事件无效
    js中!和!!的区别与用法
    form表单禁止button 提交
    Thinkphp5终端创建控制器和模型
    TP5的目录常量和路径
    sublime安装package controlller
  • 原文地址:https://www.cnblogs.com/hlkawa/p/13283642.html
Copyright © 2011-2022 走看看