观察者模式(Observer)

来源:互联网 发布:淘宝最好的二手手机店 编辑:程序博客网 时间:2024/05/16 14:59

1. 问题场景

当一个对象的状态放生改变的时候,如何让依赖于它的所有对象得到通知,并进行相应的处理?

2. UML图

这里写图片描述

Subject:目标对象,通常具有以下功能

  • 一个目标对象可以被多个观察者观察
  • 目标提供观察者注册和退订的维护
  • 当目标状态发生改变时,目标负责通知所有注册的、有效的观察者

Observer:定义观察者接口,提供目标通知时对应的更新方法,这个更新方法进行相应的业务逻辑处理,可以在这个方法回调目标对象,以获取目标对象的数据

ConcreteSubject:具体的目标对象,用来维护目标的状态,当目标状态发生改变时,通知所有注册有效的观察者,让观察者执行相应的处理

ConcreteObserver:观察者的具体对象,用来接收目标的通知,并进行相应的后续处理

3. 具体代码实现代码:

// Subject:public class Subject {    //注意:Arraylist里面可以添加null元素    private List<Observer> readers = new ArrayList<>();    public void attach(Observer reader){        if(reader != null){            readers.add(reader);        }    }    public void detach(Observer reader){        if(reader != null){            readers.remove(reader);        }    }    public void notifyAllReaders(){        if(readers.size() != 0){            //通过流的方式来访问            //因为是从Newapaper方法里调用,所有this表示Newspaper实例            readers.forEach(reader -> reader.update(this));        }    }}//Newspaper:public class Newspaper extends  Subject{    private String content;    public String getContent(){        return content;    }    //维护目标的状态    public void setContent(String content){        //内容更新之后通知所有观察者        this.content = content;        notifyAllReaders();    }}// Observer:public interface Observer {    public void update(Subject subject);}// Reader:public class Reader implements Observer {    private String name;    public void setName(String name) {        this.name = name;    }    public String getName() {        return name;    }    @Override    public void update(Subject subject) {        System.out.println(name + "收到了报纸\n 报纸的内容为: "                                          + ((Newspaper)subject).getContent() );    }}//Client端public class Client {    public static void main(String[] args) {       //创建一个报纸,作为被观察者       NewsPaper subject = new NewsPaper();       //创建阅读者,也就是观察者       Reader reader1 = new Reader();       reader1.setName("张三");       Reader reader2 = new Reader();       reader2.setName("李四");       Reader reader3 = new Reader();       reader3.setName("王五");       //注册阅读者       subject.attach(reader1);       subject.attach(reader2);       subject.attach(reader3);       //要出报纸啦       subject.setContent("本期内容是观察者模式");    }}

4. 研磨设计模式

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

观察者模式把多个订阅者称为观察者Observer,多个观察者观察的对象的被称为目标Subject。

一个目标可以有任意多个观察者对象,一旦目标的状态发生改变时,所有注册的观察者就会得到通知,然后各个观察者会对通知作出相应的处理,执行相应的业务功能处理,并使自己的状态和目标对象的状态保持一致。

观察者模式的本质:触发联动

Swing中的观察者模式:Swing组件是被观察的目标,而每个实现监听的类就是观察者,监听器的接口就是观察者的接口,在调用addXXXListener方法的时候就相当于注册观察者。当组件被单击时,状态发生改变的时候,就会产生相应的通知,会调用注册的观察者的方法,就是我们所实现的监听器的方法。

扩展:区别对待观察者

/** * 定义水质监测的目标对象 */public abstract class WaterQualitySubject {    /**     * 用来保存注册的观察者对象     */    protected List<WatcherObserver> observers = new ArrayList<WatcherObserver>();    /**     * 注册观察者对象     * @param observer 观察者对象     */    public void attach(WatcherObserver observer) {        observers.add(observer);    }    /**     * 删除观察者对象     * @param observer 观察者对象     */    public void detach(WatcherObserver observer) {        observers.remove(observer);    }    /**     * 通知相应的观察者对象     */    public abstract void notifyWatchers();    /**     * 获取水质污染的级别     * @return 水质污染的级别     */    public abstract int getPolluteLevel();}/** * 具体的水质监测对象 */public class WaterQuality extends WaterQualitySubject{    /**     * 污染的级别,0表示正常,1表示轻度污染,2表示中度污染,3表示高度污染     */    private int polluteLevel = 0;    /**     * 获取水质污染的级别     * @return 水质污染的级别     */    public int getPolluteLevel() {        return polluteLevel;    }    /**     * 当监测水质情况后,设置水质污染的级别     * @param polluteLevel 水质污染的级别     */    public void setPolluteLevel(int polluteLevel) {        this.polluteLevel = polluteLevel;        //通知相应的观察者        this.notifyWatchers();    }    /**     * 通知相应的观察者对象     */    public void notifyWatchers() {        //循环所有注册的观察者        for(WatcherObserver watcher : observers){                        //开始根据污染级别判断是否需要通知,由这里总控                        if(this.polluteLevel >= 0){                            //通知监测员做记录                            if("监测人员".equals(watcher.getJob())){                                watcher.update(this);                            }                        }                        if(this.polluteLevel >= 1){                            //通知预警人员                            if("预警人员".equals(watcher.getJob())){                                watcher.update(this);                            }                        }                        if(this.polluteLevel >= 2){                            //通知监测部门领导                           if("监测部门领导".equals(watcher.getJob())){                                watcher.update(this);                            }                        }        }    }}/** * 水质观察者接口定义 */public interface WatcherObserver {    /**     * 被通知的方法     * @param subject 传入被观察的目标对象     */    public void update(WaterQualitySubject subject);    /**     * 设置观察人员的职务     * @param job 观察人员的职务     */    public void setJob(String job);    /**     * 获取观察人员的职务     * @return 观察人员的职务     */    public String getJob();}/** * 具体的观察者实现 */public class Watcher implements WatcherObserver{    /**     * 职务     */    private String job;    public void update(WaterQualitySubject subject) {        //这里采用的是拉的方式        System.out.println(job+"获取到通知,当前污染级别为:"+subject.getPolluteLevel());    }    public String getJob() {        return this.job;    }    public void setJob(String job) {        this.job = job;    }}public class Client {    public static void main(String[] args) {        //创建水质主题对象        WaterQuality subject = new WaterQuality();        //创建几个观察者        WatcherObserver watcher1 = new Watcher();        watcher1.setJob("监测人员");        WatcherObserver watcher2 = new Watcher();        watcher2.setJob("预警人员");        WatcherObserver watcher3 = new Watcher();        watcher3.setJob("监测部门领导");        //注册观察者        subject.attach(watcher1);        subject.attach(watcher2);        subject.attach(watcher3);        //填写水质报告        System.out.println("当水质为正常的时候------------------〉");        subject.setPolluteLevel(0);        System.out.println("当水质为轻度污染的时候---------------〉");        subject.setPolluteLevel(1);        System.out.println("当水质为中度污染的时候---------------〉");        subject.setPolluteLevel(2);    }}
0 0