本文共 4233 字,大约阅读时间需要 14 分钟。
观察者模式主要是建立对象之间的一对多关系,当其中一方发生变化时,通知多个对应的对象,而具体什么时候去通知,这个就由具体的子类来实现。
下图当中给出的是观察者模式之间的结构关系图
被观察的对象的抽象接口,其中包括需要通知观察者的集合,同时也提供了,添加观察者和移除观察者方法,以及通知所有的观察者的方法。
具体的被观察者对象,当具体的被观察者发生某些变化的时候,调用通知所有观察者,同时也对其实现的接口的方法进行了实现
观察者对象接口,观察者当中提供了一个更新接口,即通知消息接口,当被观察者需要通知所有的观察者对象时,会调用该接口,并将具体的被观察者对象传递进
具体的观察者对象,其中实现了更新状态的接口,将被观察者的状态更新至观察者当中。
/** * 目标对象,作为被观察者 */public class Subject { /** * 用来保存注册的观察者对象,这里并未考虑线程安全的问题 */ private Listreaders = new ArrayList (); public void attach(Observer reader) { readers.add(reader); } public void detach(Observer reader) { readers.remove(reader); } protected void notifyObservers() { for(Observer reader : readers){ reader.update(this); } }}
public class ConcreteSubject extends Subject{ /** * 变更内容 */ private String content; /** * * 返回变更的内容 */ public String getContent() { return content; } /** * 设置变更内容,同时当变更内容发生变化,就通知所有观察者 * @param content 报纸的具体内容 */ public void setContent(String content) { this.content = content; notifyObservers(); }}
对于观察者接口
/** * 观察者 */public interface Observer { /** * 被通知的方法 * @param subject 具体的目标对象,可以获取被观察者当中的变更内容然后进行通知 */ public void update(Subject subject);}
具体的观察者
public class ConcreteObserver implements Observer{ /** * 观察者的名字 */ private String name; public void update(Subject subject) { //这是采用拉的方式 System.out.println(name+"收到消息啦,内容是==="+((ConcreteSubject)subject).getContent()); } public String getName() { return name; } public void setName(String name) { this.name = name; }}
测试类
public class Client { public static void main(String[] args) { //创建被观察者 ConcreteSubject subject = new ConcreteSubject(); //创建阅读者,也就是观察者 ConcreteObserver observer1 = new ConcreteObserver(); observer1.setName("张三"); ConcreteObserver observer2 = new ConcreteObserver(); observer2.setName("李四"); ConcreteObserver observer3 = new ConcreteObserver(); observer3.setName("王五"); //注册阅读者 subject.attach(observer1); subject.attach(observer2); subject.attach(observer3); //要出报纸啦 subject.setContent("本期内容是观察者模式"); }}打印结果张三收到消息了,内容是===本期内容是观察者模式李四收到消息了,内容是===本期内容是观察者模式王五收到消息了,内容是===本期内容是观察者模式
在JDK当中为我们提供好了被观察者对象和观察者对象,当我们需要用到观察者模式时,只需要分别实现被观察者对象和观察者对象即可
被观察者对象Observable
public class Observable { private boolean changed = false; private Vectorobs; 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) { /* * a temporary array buffer, used as a snapshot of the state of * current Observers. */ 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当中提供的被观察者对象考虑到了并发安全性问题使用了Vector,同时增加了一个状态位,用来表示,当前状态是否发生变更,如果发生没有发生变更,就不会通知观察者,如果发生变更了通知所有的观察者,同时将已经变更的状态进行重置,方便下次继续使用。
接下来看观察者对象
public interface Observer { void update(Observable o, Object arg);}
对于观察者对象来说,只有一个接口,这个方法传递两个参数,一个是被观察者对象,还有一个是自己定义的需要通知的消息,可以看到jdk设计的还是比较合理的,因为可能有时候我们的通知消息是被观察者当中获取,也有可能我们的通知消息是自己定义的。