观察者(Observer)模式

荒凉一梦 提交于 2019-11-27 11:08:48

  观察者模式又叫做发布-订阅模式(Publish.Subscribe)模式、模型-视图模式(Model/View)模式、源-监听器模式(Source/Listener)模式或从属者(Dependents)模式。

  观察者模式定义了一种一对多的依赖关系,让多个观察者同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

 1.  观察者模式结构

 一个简单的观察者模型如下:

 

角色:

抽象(Subject)主题角色:把所有的观察者维持在一个集合中,每个主题都可以有任意数量的观察者。提供一个接口,可以增加和删除观察者,主题角色又叫做被观察者(Observable)。

抽象观察者(Observer)角色:在得到主题的通知时更新自己。有时候观察者依赖于被观察者,可以将update方法修改为 void update(Subject subject)。

具体主题角色:维护所有的观察者,在具体主题的内部状态改变时给所有登记的观察者发送通知。

具体观察者角色:存储与主题的状态自恰的状态,也就是随着主题的状态改变自己的状态。

 

代码如下:

package cn.qlq.observer;

public interface Subject {
    void attach(Observer observer);

    void delete(Observer observer);

    void notifyObservers();
}

 

package cn.qlq.observer;

import java.util.Enumeration;
import java.util.List;
import java.util.Vector;

public class ConcreteSubject implements Subject {

    private List<Observer> observers = new Vector<>();

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

    @Override
    public void delete(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }

}

 

package cn.qlq.observer;

public interface Observer {

    /**
     * 
     */
    void update();

}

 

package cn.qlq.observer;

public class ConcreteObserver implements Observer {

    @Override
    public void update() {
        System.out.println(" i am notified");
    }

}

 

2.  第二种实现

  考虑上面的主题中,管理维护观察者集合的方法可以放到抽象类中去实现,因此可以将维护观察者关系的代码抽取到抽象类中,类图如下:

  这种方式与上面的区别是代表存储观察者对象的集合从连线是从抽象主题到抽象观察者。(也就是抽象主体维护抽象观察者的引用关系)

 

代码如下:

package cn.qlq.observer;

import java.util.List;
import java.util.Vector;

public abstract class Subject {
    private List<Observer> observers = new Vector<>();

    public void attach(Observer observer) {
        observers.add(observer);
    }

    public void delete(Observer observer) {
        observers.remove(observer);
    }

    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

 

 

package cn.qlq.observer;

public class ConcreteSubject extends Subject {

    private String state;

    public void changeState(String newState) {
        state = newState;
        this.notifyObservers();
    }

}

 

 

package cn.qlq.observer;

public interface Observer {

    /**
     * 
     */
    void update();

}

 

 

package cn.qlq.observer;

public class ConcreteObserver implements Observer {

    @Override
    public void update() {
        System.out.println(" i am notified");
    }

}

 

 

客户端测试代码:

package cn.qlq.observer;

public class Client {

    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        Observer observer = new ConcreteObserver();

        subject.attach(observer);

        subject.changeState("1");
    }

}

 

 

3.  Java语言对观察者模式的支持

  在Java.util保重中,提供了一个Observable类以及一个Observer接口。

Observer接口:  此接口只定义了一个update方法,当被观察者的状态发生变化时被观察者对象的notifyOeservers()方法会调用这一方法。

public interface Observer {

    void update(Observable o, Object arg);
}

 

 

Observable类:被观察者类都是该类的子类,该类有两个重要的方法:

  setChanged():  设置一个内部标记标记其状态发生变化

  notifyObsers(): 这个方法被调用时会调用所有注册的观察者的update()方法。

package java.util;

public class Observable {
    private boolean changed = false;
    private Vector obs;

    public Observable() {
        obs = new Vector();
    }
    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }

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

    public void notifyObservers() {
        notifyObservers(null);
    }

    public void notifyObservers(Object arg) {
        Object[] arrLocal;

        synchronized (this) {
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }

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

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

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

    public synchronized boolean hasChanged() {
        return changed;
    }

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

 

 

简单的使用Java对观察者模式id支持:

package cn.qlq.observer;

import java.util.Observable;

public class Watched extends Observable {

    private String data = "";

    public String getData() {
        return data;
    }

    public void changeData(String data) {
        if (!this.data.equals(data)) {
            this.data = data;
            setChanged();
        }

        notifyObservers();
    }

}

 

 

package cn.qlq.observer;

import java.util.Observable;
import java.util.Observer;

public class Watcher implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        if (o != null && (o instanceof Watched)) {
            Watched watched = (Watched) o;
            System.out.println("data changed to: " + watched.getData());
        }
    }

}

 

 

客户端代码

package cn.qlq.observer;

public class Client {

    public static void main(String[] args) {
        Watched watched = new Watched();
        Watcher watcher = new Watcher();

        watched.addObserver(watcher);

        watched.changeData("123");
        watched.changeData("123");
        watched.changeData("456");
        watched.changeData("789");
    }
}

 

结果:(虽然改变了四次值,但是有两次一样,查看源码啊在notifyObsers()中会清掉changed的值)

data changed to: 123
data changed to: 456
data changed to: 789

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!