Java设计模式之观察者模式详解

观察者模式,是一对多的关系,一个主题对应多个观察者,当这个主题发生变化的时候,所有观察着这个主题的观察者都会接收到通知来获悉主题的变化。

在现实中我们也会遇到许许多多应用观察者模式的行为,比如电视的节目频道里有时候会有暴雨天气的标志,这个标志是会随着天气的变化来显示,而我们显示的也是最新的天气标志,在这里电视频道就相当于是一个主题,而我们的电视机就是这个主题观察者,所以当这个天气标志有变化时电视上的画面也随着变化。这就是使用的观察者模式,下面就让我们用代码实现观察者模式。

首先我们需要定义主题的接口,这里面有三个方法,registerObserver、removeObserver和notifyObserver,分别是用来添加观察者、去除观察者和通知所有观察者。其中dataChange方法是只要当数据有变化就会被调用,我们需要在这个方法里调用notifyObserver去通知所有的观察者数据变化的内容,这里我们使用setSimulateDataChange方法来模拟数据的变化。

public interface Subject {

    void registerObserver(Observer observer);

    void removeObserver(Observer observer);

    void notifyObserver();
}

然后我们创建一个具体的主题类来实现这个主题接口,假设这个类是获取电视频道的信息。在这个类里面我们需要创建一个集合用来存取观察这个主题的所有观察者,接口中的registerObserver和removeObserver方法实际就是对集合的增删操作,而notifyObserver方法其实就是遍历集合通知所有的对象。

public class TelevisionData implements Subject {
    private String showName;
    private String showType;
    private ArrayList<Observer> list;

    public TelevisionData(){
        list = new ArrayList<Observer>();
    }

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

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

    @Override
    public void notifyObserver() {
        ListIterator listIterator = list.listIterator();
        while (listIterator.hasNext()){
        Observer observer = (Observer)listIterator.next();
            observer.update(showName,showType);
        }
    }

    public void dataChange(){
        notifyObserver();
    }

    //此方法用于模拟控制数据的更新,数据更新后会调用dataChange方法
    public void setSimulateDataChange(String showName,String showType){
         this.showName = showName;
         this.showType= showType;
         dataChange();
    }
}

主题部分的代码写好了,接着我们需要写观察者的代码,电视节目都播放在电视上,那我们把创建的电视类抽取出一个show方法放在Display接口中。

public interface Display {
    void show();
}

另外观察者还有一个共性,就是要接收更新到的数据进行更新,所以我们再抽取出一个update方法放到Obeserver接口中。

public interface Observer {
    void update(String showName,String showNum);
}

最后我们创建观察者的类来实现这两个接口,在这个类中showName和showType字段是用来接收主题的数据的,而subject则是要关注的主题类型引用,通过这个引用我们就可以调用registerObserver和removeObserver来控制观察者是否还要观察这个主题。当主题更新时则会调用update方法,观察者获取到更新的数据就再调用show方法显示出来。

public class John implements Observer,Display {
    private Subject subject;
    private String showName;
    private String showType;

    public John(Subject subject){
        this.subject = subject;
    }

    @Override
    public void show() {
        System.out.println("john收看的当前天气类型-" + showType);
        System.out.println("john收看的当前天气级别-" + showName);
    }

    @Override
    public void update(String showName,String showType) {
        this.showName = showName;
        this.showType = showType;
        show();
    }

    public void registerObserver(){
        this.subject.registerObserver(this);
    }


    public void removeObserver(){
        this.subject.removeObserver(this);
    }
}

public class Jack implements Observer,Display {
    private Subject subject;
    private String showName;
    private String showType;

    public Jack(Subject subject){
        this.subject = subject;
    }

    @Override
    public void show() {
        System.out.println("jack收看的当前天气类型-" + showType);
        System.out.println("jack收看的当前天气级别-" + showName);
    }

    @Override
    public void update(String showName,String showType) {
        this.showName = showName;
        this.showType = showType;
        show();
    }

    public void registerObserver(){
        this.subject.registerObserver(this);
    }


    public void removeObserver(){
        this.subject.removeObserver(this);
    }

}

下面我们来测试一下

//创建一个主题
televisionData = new TelevisionData();
    
//添加观察者
John john = new John(televisionData);
john.registerObserver();
Jack jack = new Jack(televisionData);
jack.registerObserver();
        
//模拟数据更新
changeData("大风", "5级");
changeData("暴雨", "红色");
    
public static void changeData(String showName, String showType) {
    televisionData.setSimulateDataChange(showName,showType);
}

结果:
john收看的当前天气类型-红色
john收看的当前天气级别-暴雨
jack收看的当前天气类型-红色
jack收看的当前天气级别-暴雨
john收看的当前天气类型-5级
john收看的当前天气级别-大风
jack收看的当前天气类型-5级
jack收看的当前天气级别-大风

我们再试着去掉一个观察者看它还会不会收到更新,结果是不会收到更新了

changeData("暴雨", "红色");
john.removeObserver();
changeData("大风", "5级");

结果:
john收看的当前天气类型-红色
john收看的当前天气级别-暴雨
jack收看的当前天气类型-红色
jack收看的当前天气级别-暴雨
jack收看的当前天气类型-5级
jack收看的当前天气级别-大风

总结:
观察者模式的大致原理其实就是观察者持有主题的引用来控制主题内部的集合对自己增删从而控制是否关注这个主题,而主题则通过对集合中的对象的操作,把数据的更新通知给所有的观察者。

    原文作者:设计模式
    原文地址: https://segmentfault.com/a/1190000014372254
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞