美文网首页
观察者模式(让对象能够在状态改变时被通知)

观察者模式(让对象能够在状态改变时被通知)

作者: 钉某人 | 来源:发表于2017-11-15 13:47 被阅读0次
    源码地址 https://github.com/DingMouRen/DesignPattern
    观察者模式.png
    • Subject(目标,也就是Observable可观察者)可以有任意多的观察者观察它,同时提供注册和删除观察者对象的接口
    • Observer(观察者)定义一个更新接口
    • ConcreteSubject(具体目标)将有关状态存入各ConcreteObserver对象,当它状态发生变化时,向它的各个具体观察者发出通知。
    • ConcreteObserver(具体观察者)维护这一个指向ConcreteSubject的引用;存储着有关 状态,这些状态与具体目标的状态保持一致;实现了Observer的更新接口来使自身状态与具体目标的状态保持一致。
    定义

    观察者模式定义了对象间一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。

    使用场景
    • 当对一个对象的改变需要同时改变其他对象,而又不知道具体有多少对象有待改变时
    • 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之 , 你不希望这些对象是紧密耦合的
    协作
    • 当ConcreteSubject发生任何可能导致其观察者与其本身状态不一致的改变时,它将通知它的各个观察者。
    • 在得到一个具体目标的改变通知后,ConcreteObserver对象可向目标对象查询信息。ConcreteObserver使用这些信息来使它的状态与目标对象的状态一致。
    举个例子

    我们有一个对象ConcreteSubject,可以获取到环境中的温度、湿度和压力,也就是被观察者(目标),这里有两个对象ConcreteObserver系列,用途是显示环境中的温度、湿度和压力,我们要求在ConcreteSubject的数据发生变化时,ConcreteObserver系列的要同时更新数据。

    
    //目标接口:1.定义注册接口  2.定义注销接口 3.定义发送通知的接口
    public interface Subject {
        void registerObserver(Observer observer);//注册观察者
        void removeObserver(Observer observer);//注销观察者
        void notifyObservers();//目标状态变化时,调用这个方法通知所有观察者
        void notifyObservers(Object arg);//也可以通知所有的观察者,另外可以携带其他的数据
    }
    
    //具体目标:1.存储最新的状态数据 2.维护着所有观察者的集合 3.一旦数据更新,向所有观察者发送通知
    public class ConcreteSubject implements Subject {
        private ArrayList<Observer> observers;//存储注册的观察者对象,ArrayList是线程不安全的,Vector是线程安全的
        private float temperature;//温度
        private float humidity;//湿度
        private float pressure;//压力
    
        public ConcreteSubject() {
            this.observers = new ArrayList();
        }
    
        @Override
        public void registerObserver(Observer observer) {
            if (observer == null) throw  new NullPointerException();
            if (!observers.contains(observer)) observers.add(observer);//判断是否有这个观察者,不然会被通知两回
        }
    
        @Override
        public void removeObserver(Observer observer) {
            int index = observers.indexOf(observer);
            if (index >= 0) observers.remove(index);
        }
    
        @Override
        public void notifyObservers() {
           notifyObservers(null);
        }
    
        @Override
        public void notifyObservers(Object arg) {
            for(Observer observer : observers){
                observer.update(this,arg);
            }
        }
    
        public void setNewData(float temperature,float humidity,float pressure){
            this.temperature =temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            measurementsChanged();
        }
    
        private void measurementsChanged(){
            notifyObservers();
        }
    
        public float getTemperature() {
            return temperature;
        }
    
        public float getHumidity() {
            return humidity;
        }
    
        public float getPressure() {
            return pressure;
        }
    }
    
    //观察者接口
    public interface Observer {
        void update(Subject subject,Object arg);
    }
    //用来显示最新的数据的接口
    public interface DisplayNewData {
        void display();
    }
    //具体观察者:1.维护着一个目标的引用  2.实现观察者接口,更新状态与目标状态一致
    public class ConcreteObserver_1 implements Observer,DisplayNewData {
        private Subject subject;
        private float temperature;//温度
        private float humidity;//湿度
        private float pressure;//压力
    
        public ConcreteObserver_1(Subject subject) {//传入目标subject用来注册观察者,自然也可以删除观察者
            this.subject = subject;
            this.subject.registerObserver(this);
        }
    
        /**
         * 这里获取的更新数据的方式是“拉”,我们想要什么数据,就通过get方法获得,而不是目标把数据主动推给观察者的
         * @param subject
         * @param arg
         */
        @Override
        public void update(Subject subject, Object arg) {
            ConcreteSubject concreteSubject = (ConcreteSubject) subject;
            this.temperature = concreteSubject.getTemperature();
            this.humidity = concreteSubject.getHumidity();
            this.pressure = concreteSubject.getPressure();
            display();
        }
    
        @Override
        public void display() {
            System.out.println(this.getClass().getSimpleName()+"最新的数据:\n温度:"+temperature+"℃ 湿度:"+humidity+"% 压力:"+pressure);
        }
    }
    
    

    使用

     public static void main(String[] args) {
            //创建目标,可观察者
            ConcreteSubject concreteSubject = new ConcreteSubject();
            //创建观察者并注册
            ConcreteObserver_1 observer_1 = new ConcreteObserver_1(concreteSubject);
            ConcreteObserver_2 observer_2 = new ConcreteObserver_2(concreteSubject);
            //更新数据
            concreteSubject.setNewData(1,2,3);
        }
    

    java中的java.util.Observable的缺点:

    • 我们想同时具有Observable类和另一个超类的行为时,就会陷入困难,java是不支持多重继承的,限制了Observable的复用潜力
    • Observable中的setChanged()被protected修饰的,只能通过继承,违反OO设计原则:多用组合,少用继承
    总结

    优点

    • 观察者与被观者之间是抽象耦合,可以应对业务变化
    • 增强系统灵活性,更易扩展
      缺点
    • 一个观察者卡顿,会影响整体的执行效率,在这种情况下,可以采用异步的方式。

    相关文章

      网友评论

          本文标题:观察者模式(让对象能够在状态改变时被通知)

          本文链接:https://www.haomeiwen.com/subject/eoicvxtx.html