返回 登录
0

Java设计模式之观察者模式

观察者模式:

用报纸订阅的方式来说明:

1、报社的业务就是出版报纸

2、向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来。只要你是他们的订户,就会一直收到报纸

3、当你不想再看报纸的时候,取消订阅,他们就不会再送来新报纸

4、只要报社还在运营,就会一直有人向他们订阅报纸或者取消订阅报纸

观察者模式的流程跟报纸订阅方式一致,即:观察者模式=出版者+订阅者,只是名称不一样,出版者改称为“主题”(Subject),订阅者改称为“观察者”(Observer)。

观察者定义:

观察者模式定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖者都会受到通知并自动更新。

主题接口(Subject):对象使用此接口注册为观察者,或者把自己从观察者中删除。

具体主题(ConcreteSubject):一个具体主题总是实现主题接口,除了注册*和撤销方法以外,具体主题还实现了notifyObserves()方法,此方法用于在状态改变时更新所有当前观察者。

观察者(Observer):为那些在目标发生改变时需获得通知的对象定义更新的接口

具体观察者(ConcreteObserver):具体观察者实现了观察者Observer接口,并注册具体主题,以便接收更新。

观察者模式提供了一种对象设计,让主题和观察者之间松耦合,当两个对象之间松耦合,它们依然可以交互,但是不太清楚彼此的细节,主题只知道观察者实现了Observer接口,不需要知道观察者的具体类是谁,做了些什么其他的细节。

观察者实例:

通过ConcreteObserver注册两个观察者ConcreteObserverA和ConcreteObserverB,一旦被观察者有更新,两个观察者会立刻收到更新通知。具体代码如下:

声明Subject主题接口,Subject.java:

public interface Subject {

    void registerObserver(Observer observer);

    void removeObserver(Observer observer);

    void notifyObservers();

}

声明ConcreteObserver具体主题,NetConcreteSubject.java:

public class NetConcreteSubject implements Subject {

    private List<Observer> observers;
    private ObserverBean bean;

    public NetConcreteSubject() {
        observers = new ArrayList<>();
    }

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        int pos = observers.indexOf(observer);
        if (pos > 0) {
            observers.remove(pos);
        }
    }

    @Override
    public void notifyObservers() {
        if (bean == null) return;
        for (int i = 0; i < observers.size(); i++) {
            Observer observer = observers.get(i);
            observer.update(bean);
        }

    }

    public void setStatusChanged(ObserverBean bean) {
        this.bean = bean;
        notifyObservers();
    }
}

声明观察者接口, Observer.java:

public interface Observer {

    void update(Object obj);
}

声明具体观察者类,ConcreteObserverA.java:

public class ConcreteObserverA implements Observer {

    @Override
    public void update(Object obj) {
        if (obj instanceof ObserverBean) {
            ObserverBean bean = (ObserverBean) obj;
            System.out.print("ConcreteObserverA 网络类型:"
                    + bean.netType + ",网络状态:" + bean.netStatus + "\n");
        }
    }
}

ConcreteObserverB.java:

public class ConcreteObserverB implements Observer {

    @Override
    public void update(Object obj) {
        if (obj instanceof ObserverBean) {
            ObserverBean bean = (ObserverBean) obj;
            System.out.print("ConcreteObserverB 网络类型:"
                    + bean.netType + ",网络状态:" + bean.netStatus + "\n");
        }
    }
}

调用过程:

public static void main(String[] args) {

       //初始化主题(被观察者)
       NetConcreteSubject subject = new NetConcreteSubject();
       //初始化观察者A
       ConcreteObserverA observerA = new ConcreteObserverA();
       //初始化观察者B
       ConcreteObserverB observerB = new ConcreteObserverB();
       //注册观察者A
       subject.registerObserver(observerA);
       //注册观察者B
       subject.registerObserver(observerB);
       //通知所有观察者数据有更新
       ObserverBean bean = new ObserverBean("wifi", "有网");
       subject.setStatusChanged(bean);
   }

运行结果:

ConcreteObserverA 网络类型:wifi,网络状态:有网
ConcreteObserverB 网络类型:wifi,网络状态:有网

Java内置观察者:

Observable.java:

/**
 * Java学习交流QQ群:589809992 我们一起学Java!
 */
public class Observable {
    private boolean changed = false;
    private Vector<Observer> obs = new Vector();

    public Observable() {
    }

    public synchronized void addObserver(Observer var1) {
        if(var1 == null) {
            throw new NullPointerException();
        } else {
            if(!this.obs.contains(var1)) {
                this.obs.addElement(var1);
            }

        }
    }

    public synchronized void deleteObserver(Observer var1) {
        this.obs.removeElement(var1);
    }

    public void notifyObservers() {
        this.notifyObservers((Object)null);
    }

    public void notifyObservers(Object var1) {
        Object[] var2;
        synchronized(this) {
            if(!this.changed) {
                return;
            }

            var2 = this.obs.toArray();
            this.clearChanged();
        }

        for(int var3 = var2.length - 1; var3 >= 0; --var3) {
            ((Observer)var2[var3]).update(this, var1);
        }

    }

    public synchronized void deleteObservers() {
        this.obs.removeAllElements();
    }

    protected synchronized void setChanged() {
        this.changed = true;
    }

    protected synchronized void clearChanged() {
        this.changed = false;
    }

    public synchronized boolean hasChanged() {
        return this.changed;
    }

    public synchronized int countObservers() {
        return this.obs.size();
    }
}

Observer.java:

public interface Observer {
    void update(Observable var1, Object var2);
}

上面的Observer和Observable类都位于java.util目录中,是JDK中已经写好的,那么我们可以直接拿来用了:

主题类NetSubject.java:

public class NetSubject extends Observable {

    public void setNetChanged(ObserverBean bean){
        setChanged();
        notifyObservers(bean);
    }
}

观察者SystemObserverA.java:

public class SystemObserverA implements Observer {

    @Override
    public void update(Observable observable, Object o) {
        if (o instanceof ObserverBean
                && observable instanceof NetSubject) {
            ObserverBean bean = (ObserverBean) o;
            System.out.print("ConcreteObserverA 网络类型:"
                    + bean.netType + ",网络状态:" + bean.netStatus + "\n");
        }
    }
}

观察者SystemObserverB.java:

/**
 * Java学习交流QQ群:589809992 我们一起学Java!
 */
public class SystemObserverB implements Observer {

    @Override
    public void update(Observable observable, Object o) {
        if (o instanceof ObserverBean
                && observable instanceof NetSubject) {
            ObserverBean bean = (ObserverBean) o;
            System.out.print("ConcreteObserverB 网络类型:"
                    + bean.netType + ",网络状态:" + bean.netStatus + "\n");
        }
    }
}

执行程序:

//初始化主题(被观察者)
   NetSubject subject = new NetSubject();
   //初始化观察者A
   SystemObserverA observerA = new SystemObserverA();
   //初始化观察者B
   SystemObserverB observerB = new SystemObserverB();
   //注册观察者A
   subject.addObserver(observerA);
   //注册观察者B
   subject.addObserver(observerB);
   //通知观察者有更新
   ObserverBean bean = new ObserverBean("4G流量", "有网");
   subject.setNetChanged(bean);

运行结果:

ConcreteObserverB 网络类型:4G流量,网络状态:有网
ConcreteObserverA 网络类型:4G流量,网络状态:有网

注意:
当使用JDK内置观察者模式时,当需要通知观察者更新数据时,首先需要调用setChanged()来改变状态,否则观察者不会收到任何更新通知。为什么会这样呢,来看下JDK中的源码就知道了:

private boolean changed = false;

 protected synchronized void setChanged() {
        this.changed = true;
    }

  public void notifyObservers(Object var1) {
        Object[] var2;
        synchronized(this) {
           //如果changed为false,将直接返回
            if(!this.changed) {
                return;
            }

            var2 = this.obs.toArray();
            this.clearChanged();
        }

        for(int var3 = var2.length - 1; var3 >= 0; --var3) {
            ((Observer)var2[var3]).update(this, var1);
        }

    }

通过setChanged()将changed设置为true,否则当调用notifyObservers(Object var1)将没有任何作用。

使用JDK内置观察者模式看似程序更简单了,但缺点也暴露出来了:
1、Observable是一个类,而不是一个接口,导致Observable类的扩展性不高,限制了它的使用和复用。
2、Observable将某些方法保护了起来(setChanged()和clearChanged()为protected),这意味着除非继承自Observable,否则将有关键的方法不能调用。导致无法通过组合的方式使其它类获得Observable类的功能

所以,如果JDK内置的观察者模式符合你的需求,那么可以尽情的使用内置的观察者模式,否则应该自己实现一套观察者模式。

评论