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

  • 相关阅读:
    Scrapy 概览笔记
    Python 依赖版本控制 (requirements.txt 文件生成和使用)
    Python 虚拟空间的使用
    macOS 所有版本 JDK 安装指南 (with Homebrew)
    鉴权那些事
    Java 位运算符和 int 类型的实现
    ASP.NET Core 入门教程 5、ASP.NET Core MVC 视图传值入门
    如何做好一次知识或技术分享
    ASP.NET Core 入门教程 4、ASP.NET Core MVC控制器入门
    ASP.NET Core 入门教程 3、ASP.NET Core MVC路由入门
  • 原文地址:https://www.cnblogs.com/hlkawa/p/13283642.html
Copyright © 2020-2023  润新知