• 观察者模式


    在处理类之间的多对一的依赖关系时,观察者设计模式应运而生了,它的出现实现了代码的瘦身,类之间的解耦,本文分三部分:

    • 非观察者模式的多对一的依赖处理
    • 观察者模式对多对一依赖处理的优化
    • Java内置的观察者

    假设场景: 前端用户向后端服务器发送不同的请求,后端的Selector区的分不同的请求,回调不同的Handler处理请求, 下面的示例代码

    非观察者

    当Selector发现数据改变时,想要回调Handler的方法的前提是它要维护一个Handler的引用, 我们在构造函数中传递进去

    @Data
    public class Selector {
        private String username; 
        private String password; 
    
        private Handler1 currentConditions;
    
        public Selector(Handler1 currentConditions) {
            this.currentConditions = new Handler1();
        }
    
        public void datachange() {
            currentConditions.update(getUsername(),getPassword());
        }
    
        // 添加假数据
        public void setData(String username,String password){
            this.username=username;
            this.password=password;
            datachange();
        }
    
    }
    

    Handkler 的成员变量和Selector一样, 同时真正干活的人是handler, 它里面只有干活的方法以及承载数据的字段, 干活的方法会被回调, 字段由Selector负责初始化

    public class Handler1 {
        private String  username;
        private String password;
    
        public void update( String  username, String  password){
            this.username=username;
            this.password=password;
            display();
        }
    
        public void display(){
            System.out.println("Handler1 : username"+ username);
            System.out.println("Handler1 : password"+username);
        }
    }
    

    测试:

    public class text {
        public static void main(String[] args) {
            Handler1 currentConditions = new Handler1();
            Selector Data = new Selector(currentConditions);
            Data.setData("张三","123");
        }
    }
    

    上面的设计方法实现了,当Selector发现新的数据改变时,回调指定的handler的需求,但是缺点很快就暴露出来, Handler引用以构造方法的形式在Selector维护,如果有100个handler, 是不是意味着Selector的构造函数重载100份?


    观察者模式

    观察者解决了上面的问题,在观察者模式中有两个角色的划分,1.SubJect 2.Observer, 其中 SubJect负责回调Observer提供的方法处理数据, Observer就是观察者,伺机而动, 它之所以能够实现两者的解耦,实现代码的瘦身,精华就是在Subject的构造函数不再维护单一的某一个Observer的引用,而是一个泛型是为Observer类型的集合, 为了防止把非观察者的对象添加到集合中, 故 在原有的基础上,向上进行了一层抽象,把Subject和Observer设计成接口,Subject提供了注册/移除/通知观察者的方法,通知哪个方法呢? 于是Observer接口中提供了需要被回调的抽象方法, 做完这层封装之后,就有了这个观察者体系, 所有的观察者必须实现Observer接口,重写它的方法,任何回调观察者的类,也必须实现Subject,重写它的方法

    实例代码:

    public interface Subject {
        public void registerObserver(Observer o);
        public void removeObserver(Observer o);
        public void notifyObserver();
    }
    
    public interface Observer {
        public void update(String m,String p);
    }
    
    

    Subject的实现类:

    @Data
    public class Selector implements Subject {
        private String username;
        private String password;
    
        private ArrayList<Observer> list;
    
        public Selector() {
          this.list = new ArrayList<Observer>();
        }
    
        // 添加假数据
        public void setData( String username, String password){
            this.username=username;
            this.password=password;
    
        }
    
        @Override
        public void registerObserver(Observer o) {
            list.add(o);
        }
    
        @Override
        public void removeObserver(Observer o) {
            list.remove(o);
        }
    
        @Override
        public void notifyObserver() {
            list.forEach(s->s.update(getPassword(),getUsername()));
        }
    }
    
    

    Observer的实现:

    public class Handler1 implements Observer {
        private String username;
        private String password;
    
        @Override
        public void update( String username,String password){
            this.username=username;
            this.password=password;
            display();
        }
    
        public void display(){
            System.out.println("  Handler1    "+ username);
            System.out.println("  Handler1    "+password);
        }
    }
    

    测试:

    public class text {
        public static void main(String[] args) {
            Handler1 secondConditions = new Handler1();
            Selector Data = new Selector();
            // 注册观察者
              Data.registerObserver(secondConditions);
              Data.setData("张三","123");
              Data.notifyObserver();
        }
    }
    

    我们自己实现的观察者函数回调的特性: : 虽然实现我们一开始的需求,但是可以看到,数据是在Subject端进行初始化的, 并没有传递到观察端,由观察者自主分配数据


    java内置的观察者

    java内置的观察中同样分为两种角色,1.Obserable 2.Observer 其中Observer是观察者,同样不变的是,他是个接口

    但是: Obserable是一个抽象类, java为我们实现了 注册/移除,通知的方法, 在不允许多继承的java中,抽象类是有缺点的,这使得当前类不能再继承其他类

    此外: 相对于我们自定义的观察者, 它做到了把数据传递到 观察者客户端,任由观察者自主的分配这些数据

    如何使用:
    对于Obserable来说, 继承他

    • 由于java实现了主要的方法, 我们只关注如何使用这几个方法就行了
    • 1: 在回调之前 , 必须先使用 this.setChanged(); 否则信息不会通知到观察者
    • 2: 通知的方法 this.notifyObservers(Object obj));
    @Data
    public class Selector extends Observable {
        private String username;
        private String  password;
    
        // 添加假数据
        public void setData( String username, String password) {
            this.username = username;
            this.password = password;
            datachange();
        }
    
        // 当信息更改, 就推送
        public void datachange() {
            // todo 加上这一条,当有信息改变时, 就执行
            this.setChanged();
            // 通知时,把信息同步推送给观察者
           this.notifyObservers(new Data(getUsername(),getPassword()));
        }
    
        @lombok.Data
        public class Data {
            private String username;
            private String  password;
    
            public Data( String username, String password) {
                this.username = username;
                this.password = password;
            }
        }
    }
    

    观察者: 继承Observer, 重写它被回调的方法

    public class Handler1 implements Observer {
        private String username; 
        private String password;  
    
        @Override
        public void update(Observable observable, Object arg0) {
            this.password = ((Selector.Data) (arg0)).getPassword();
            this.username = ((Selector.Data) (arg0)).getUsername();
            display();
        }
    
        public void display() {
            System.out.println("Handler1 :    " + username);
            System.out.println("Handler1 : " + password);
        }
    }
    
    

    测试

    public class text {
        public static void main(String[] args) {
            Handler1 handler1 = new Handler1();
            Selector weatherData = new Selector();
            // 先注册的观察者,后执行
            weatherData.addObserver(handler1);
            weatherData.setData("张三","123");
        }
    }
    
  • 相关阅读:
    seata 1.3.0 seata Global lock wait timeout
    Tika解析word文件
    我的第一款微信小程序:iteye附件下载器,希望大家好好爱惜
    读书《尸检报告》 [英]卡拉·瓦伦丁 / 中信出版集团2019-08
    读书《另一种选择》 [美] 谢丽尔·桑德伯格 / 中信出版集团2017-08
    读书《不朽的失眠》 张晓风 / 四川人民出版社2018-09
    Uniapp 修改内置组件样式无效解决方法
    Android studio中.9图片的含义及制作教程
    Diff算法
    js new一个对象的过程,实现一个简单的new方法
  • 原文地址:https://www.cnblogs.com/ZhuChangwu/p/11159285.html
Copyright © 2020-2023  润新知