zoukankan      html  css  js  c++  java
  • 设计模式之美学习-行为型-观察者模式(二十六)

    什么是观察者模式

    在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知,被依赖对象为被观察者,依赖对象为观察者

    在实际开发中有多种叫法::Subject-Observer、Publisher-Subscriber、Producer-Consumer、EventEmitter-EventListener、Dispatcher-Listener

    设计模式其实要干的事情就是解耦。创建型模式是将创建和使用代码解耦,结构型模式是将不同功能代码解耦,行为型模式是将不同的行为代码解耦,具体到观察者模式,它是将观察者和被观察者代码解耦。借助设计模式,我们利用更好的代码结构,将一大坨代码拆分成职责更单一的小类,让其满足开闭原则、高内聚松耦合等特性,以此来控制和应对代码的复杂性,提高代码的可扩展性

    常见的应用方式

    /**
     * 定义观察者接口
     */
    public interface Subject {
        //注册观察者
        void registerObserver(Observer observer);
        //删除观察者
        void removeObserver(Observer observer);
        //发起通知
        void notifyObservers(Message message);
    }
    
    /**
     * 定义被观察者接口
     */
    public interface Observer {
        void update(Message message);
    }
    
    public class ConcreteSubject implements Subject {
        //存储被观察者
        private List<Observer> observers = new ArrayList<Observer>();
    
        //注册
        @Override
        public void registerObserver(Observer observer) {
            observers.add(observer);
        }
       //删除
        @Override
        public void removeObserver(Observer observer) {
            observers.remove(observer);
        }
       //发起通知
        @Override
        public void notifyObservers(Message message) {
            //循环调用被观察者通知方法
            for (Observer observer : observers) {
                observer.update(message);
            }
        }
    
    }
    
    //被观察者实现1
    public class ConcreteObserverOne implements Observer {
        //接收通知
        @Override
        public void update(Message message) {
            //TODO: 获取消息通知,执行自己的逻辑...
            System.out.println("ConcreteObserverOne is notified.");
        }
    }
    
    //被观察者实现
    public class ConcreteObserverTwo implements Observer {
        //接收通知
        @Override
        public void update(Message message) {
            //TODO: 获取消息通知,执行自己的逻辑...
            System.out.println("ConcreteObserverTwo is notified.");
        }
    }
    
    public class Demo {
        public static void main(String[] args) {
            //创建一个观察者对象
            ConcreteSubject subject = new ConcreteSubject();
            //注册被观察者
            subject.registerObserver(new ConcreteObserverOne());
            subject.registerObserver(new ConcreteObserverTwo());
            //发起通知
            subject.notifyObservers(new Message());
        }
    }

    注册场景应用

    需求

    假设我们在开发一个 P2P 投资理财系统,用户注册成功之后,我们会给用户发放投资体验金。代码实现大致是下面这个样子的

    原始代码

    public class UserController {
        private UserService userService; // 依赖注入
        private PromotionService promotionService; // 依赖注入
    
        public Long register(String telephone, String password) {
            //省略输入参数的校验代码
            //注册
            long userId = userService.register(telephone, password);
            //发放体验金
            promotionService.issueNewUserExperienceCash(userId);
            return userId;
        }
    }

    注册里面做了2个事情一个是注册一个是发放体验金违反单一职责原则,如果不大量更改以下代码可以接收.

    如果需要大量更改,比如后续注册成功增加发送短信提醒,我们再register方法增加一行发送短信违反了开闭原则,我们可以通过观察者模式来实现

    重构后

    //被观察者抽象接口
    public interface RegObserver {
        void handleRegSuccess(long userId);
    }
    
    //发送体验金
    public class RegPromotionObserver implements RegObserver {
        private PromotionService promotionService; // 依赖注入
    
        @Override
        public void handleRegSuccess(long userId) {
            promotionService.issueNewUserExperienceCash(userId);
        }
    }
    
    //发送短信
    public class RegNotificationObserver implements RegObserver {
        private NotificationService notificationService;
    
        @Override
        public void handleRegSuccess(long userId) {
            notificationService.sendInboxMessage(userId, "Welcome...");
        }
    }
    
    public class UserController {
        private UserService userService; // 依赖注入
        //被观察者
        private List<RegObserver> regObservers = new ArrayList<>();
    
        // 一次性设置好,之后也不可能动态的修改
        public void setRegObservers(List<RegObserver> observers) {
            regObservers.addAll(observers);
        }
    
        public Long register(String telephone, String password) {
            //省略输入参数的校验代码
            //省略userService.register()异常的try-catch代码
            long userId = userService.register(telephone, password);
            //注册成功 通知被观察者
            for (RegObserver observer : regObservers) {
                observer.handleRegSuccess(userId);
            }
    
            return userId;
        }
    }

    异步非阻塞模式

    可以查看Guava EventBus使用

  • 相关阅读:
    PowerDesigner应用02 逆向工程之导出PDM文件前过滤元数据(表、视图、存储过程等)
    PowerDesigner应用01 逆向工程之配置数据源并导出PDM文件
    CLR查找和加载程序集的方式(二) 流程图
    CLR查找和加载程序集的方式(一)
    C#控制台程序入口函数 Main(string[] args) 参数详解
    INotifyPropertyChanged 接口 CallerMemberName属性
    INotifyPropertyChanged 接口
    SQL Server 中执行Shell脚本计算本地文件的内容大小
    统计一个数据库中,无记录的表的sql语句
    SQL 性能优化 总结
  • 原文地址:https://www.cnblogs.com/LQBlog/p/12671716.html
Copyright © 2011-2022 走看看