1. 问题场景

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

2. UML图

观察者模式(Observer)_目标对象

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);
    }
}
Java高级架构干货|学习观察者模式(Observer)_一对多_02观察者模式(Observer)_观察者模式_03