zoukankan      html  css  js  c++  java
  • 观察者模式(Observer Pattern)

    观察者模式,主要就是一个地方的改变,需要通知多个其他依赖方,例如,一个订单的状态发生变更,后续的物流、保险等许多系统都需要用到这个变化值,那么就可以考虑使用观察者模式(这里不考虑跨系统问题)

    在JDK中,Swing API就用到了观察者模式,放一个按钮被触发时,所有需要依赖该通知的地方,都会收到通知事件,收到通知事件后,做相应的处理。

    在观察者模式中,一般存在三个对象,一个是通知对象,一个是主题Subject,一个是具体的需要被通知的对象。

    接下来就演示一个观察者模式

    示例:一个天气监测站,每有数据更新,则通知各个显示站,显示站根据自己的需求进行展示内容

    首先,创建一个主题接口,用来注册、移除观察者,同时可以通知观察者

    package lcl.mm.pattern.observer.demo1;
    
    public interface Subject {
        /**
         * 注册一个观察者
         * @param o
         */
        public void registerObserver(MyObserver o);
    
        /**
         * 移除一个观察者
         * @param o
         */
        public void removeOberver(MyObserver o);
    
        /**
         * 通知观察者
         */
        public void notifyObserver();
    }

    然后,创建一个展示内容的接口

    package lcl.mm.pattern.observer.demo1;
    
    public interface DisplayElement {
        public void display();
    }

    接着,创建一个更新接口

    package lcl.mm.pattern.observer.demo1;
    
    public interface MyObserver {
        public void update(int temp,int humidity, int pressure);
    }

    创建一个通知的对象,该对象实现Subject接口,对注册、移除和通知观察者接口进行实现,观察通知着的实现是循环所有观察者进行调用更新方法,然后还提供一个供天气监测站调用的接口

    package lcl.mm.pattern.observer.demo1;
    
    import java.util.ArrayList;
    
    public class WeatherData implements Subject{
    
        private ArrayList<MyObserver> observers = new ArrayList<>();
        private int temperature;
        private int humidity;
        private int pressure;
    
        @Override
        public void registerObserver(MyObserver o) {
            observers.add(o);
        }
    
        @Override
        public void removeOberver(MyObserver o) {
            int i = observers.indexOf(o);
            if(i>=0){
                observers.remove(i);
            }
        }
    
        @Override
        public void notifyObserver() {
            for (MyObserver o:observers) {
                o.update(temperature,humidity,pressure);
            }
        }
    
        /**
         * 数据变更
         */
        public void setChangeed(int temperature,int humidity, int pressure){
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            this.notifyObserver();
        }
    }

    最后就是创建观察者对象,该对象实现数据更新接口和显示接口,在显示接口实现方法中,按照自己的需求显示内容;在更新接口实现方法中,按照自己的需求做数据更新并调用显示方法(这里写了两个观察者)

    package lcl.mm.pattern.observer.demo1;
    
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    public class CurrentConditionDisplay implements MyObserver,DisplayElement {
    
        private int temperature;
        private int humidity;
        private int pressure;
        private WeatherData weatherData;
    
        @Override
        public void display() {
            log.info("CurrentConditionDisplay:{},{},{}",temperature,humidity,pressure);
        }
    
        @Override
        public void update(int temp, int humidity, int pressure) {
            this.temperature = temp;
            this.humidity = humidity;
            this.pressure = pressure;
            display();
        }
    
        public CurrentConditionDisplay(WeatherData weatherData){
            this.weatherData = weatherData;
            weatherData.registerObserver(this);
        }
    }
    package lcl.mm.pattern.observer.demo1;
    
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    public class TotalConditionDisplay implements MyObserver,DisplayElement {
    
        private int temperature;
        private int humidity;
        private int pressure;
        private WeatherData weatherData;
    
        @Override
        public void display() {
            log.info("TotalConditionDisplay:{},{},{}",temperature,humidity,pressure);
        }
    
        @Override
        public void update(int temp, int humidity, int pressure) {
            this.temperature = temp*10;
            this.humidity = humidity*10;
            this.pressure = pressure*10;
            display();
        }
    
        public TotalConditionDisplay(WeatherData weatherData){
            this.weatherData = weatherData;
            weatherData.registerObserver(this);
        }
    }

    最后,就是测试,写一个测试方法,通知上述两个观察者,然后再演示剔除一个观察者后再通知所有观察者

        @Test
        void observerTest1(){
            WeatherData weatherData = new WeatherData();
            CurrentConditionDisplay currentConditionDisplay = new CurrentConditionDisplay(weatherData);
            TotalConditionDisplay totalConditionDisplay = new TotalConditionDisplay(weatherData);
            log.info("register observer:CurrentConditionDisplay,TotalConditionDisplay");
            weatherData.setChangeed(1,2,3);
            weatherData.setChangeed(4,5,6);
            log.info("remove register currentConditionDisplay");
            weatherData.removeOberver(currentConditionDisplay);
            weatherData.setChangeed(5,6,7);
        }

    输出结果

     其实,在jdk中,已经提供了观察者模式的相关类java.util.Observable和java.util.Observer,那么使用JDK提供的实现类来写上述观察者模式,写法如下:

    显示的接口,与上述一致

    package lcl.mm.pattern.observer.demo2;
    
    public interface DisplayElement2 {
        public void display();
    }

    创建一个传输数据对象,该对象需要继承java.util.Observable,在该类的调用前notifyObservers()通知观察者之前,需要先调用setChanged();将变更状态置为true,否则不会通知观察者。这是为了给我们提供一个灵活的更新限制,比如说,小于5的情况下,我们就不更新。

    package lcl.mm.pattern.observer.demo2;
    
    import java.util.Observable;
    
    public class WeatherData2 extends Observable {
    
        private int temperature;
        private int humidity;
        private int pressure;
    
        public void changed(int temperature, int humidity, int pressure){
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            notifyChanged();
        }
    
        private void notifyChanged(){
            setChanged();
            notifyObservers();
        }
    
        public int getTemperature(){
            return temperature;
        }
    
        public int getHumidity(){
            return  humidity;
        }
    
        public int getPressure(){
            return pressure;
        }
    }

    然后,写两个观察者,需要实现java.util.Observer接口和自己创建的展示接口

    package lcl.mm.pattern.observer.demo2;
    
    import lombok.extern.slf4j.Slf4j;
    
    import java.util.Observable;
    import java.util.Observer;
    
    @Slf4j
    public class CurrentConditionDisplay2 implements Observer, DisplayElement2 {
    
        private int temperature;
        private int humidity;
        private int pressure;
        private Observable observable;
        @Override
        public void display() {
            log.info("CurrentConditionDisplay2:{},{},{}",temperature,humidity,pressure);
        }
    
        public CurrentConditionDisplay2(Observable observable){
            this.observable = observable;
            observable.addObserver(this);
        }
    
    
        @Override
        public void update(Observable o, Object arg) {
            if(o instanceof WeatherData2){
                WeatherData2 weatherData = (WeatherData2) o;
                this.temperature = weatherData.getTemperature();
                this.humidity = weatherData.getHumidity();
                this.pressure = weatherData.getPressure();
                display();
            }
        }
    }
    package lcl.mm.pattern.observer.demo2;
    
    import lombok.extern.slf4j.Slf4j;
    
    import java.util.Observable;
    import java.util.Observer;
    
    @Slf4j
    public class TotalConditionDisplay2 implements Observer, DisplayElement2 {
    
        private int temperature;
        private int humidity;
        private int pressure;
        private Observable observable;
    
        @Override
        public void display() {
            log.info("TotalConditionDisplay2:{},{},{}",temperature,humidity,pressure);
        }
    
    
        public TotalConditionDisplay2(Observable observable){
            this.observable = observable;
            observable.addObserver(this);
        }
    
        @Override
        public void update(Observable o, Object arg) {
            if(o instanceof WeatherData2){
                WeatherData2 weatherData = (WeatherData2) o;
                this.temperature = weatherData.getTemperature();
                this.humidity = weatherData.getHumidity();
                this.pressure = weatherData.getPressure();
                display();
            }
        }
    }

    最后,编写测试方法

        @Test
        void observerTest2(){
            WeatherData2 weatherData = new WeatherData2();
            log.info("register observer:CurrentConditionDisplay,TotalConditionDisplay");
            CurrentConditionDisplay2 currentConditionDisplay2 = new CurrentConditionDisplay2(weatherData);
            TotalConditionDisplay2 totalConditionDisplay2 = new TotalConditionDisplay2(weatherData);
            weatherData.changed(1,2,3);
            weatherData.changed(4,5,6);
    
            
            log.info("remove register currentConditionDisplay");
            weatherData.deleteObserver(currentConditionDisplay2);
            weatherData.changed(7,8,9);
        }

    测试:

  • 相关阅读:
    【js】this=>>4种用法
    【js】接口实现代码
    【es6】object.is()&&==&&===
    js apply&&call
    【javascript=>>DOM】=>>Attribute与Property的区别
    Android ListView刷新问题
    Android EditText自动换行
    Android 状态栏隐藏 ( 全屏 )
    Android 取得手机屏幕大小
    Android中使用代码改变背景颜色
  • 原文地址:https://www.cnblogs.com/liconglong/p/13222595.html
Copyright © 2011-2022 走看看