设计模式之观察者模式
2018-01-13 17:20
162 查看
在学习java AWT或者Swing的时候,我们知道,如果为按钮添加了监听器,那么在我们点击按钮的时候,就可以触发一定的事件。大致过程如下:当点击一个按钮的时候就会产生一个事件,然后检查是否有与该按钮关联的事件处理器(实际上就是一个方法),如果没有,那么什么都不执行;如果有,就会将该事件传递给与该按钮相关联的处理器方法,作为该方法的参数,之后该事件处理器方法就会“自动”得到调用,并且该方法可以使用传递过来的ActionEvent对象进而获得事件发生时与该事件及事件源相关联的那些信息。
其中,“自动调用”是不准确的,确切地说来还是按钮去调用了与之关联的处理器方法。
这其中,也涉及到了一种设计模式————观察者模式
观察者模式:一对多的依赖关系,多个观察者对象同时监听某一主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,让他们能够自动更新自己。
观察者模式的组成:
1.抽象主题角色(也就是被观察者):把所有观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类或接口来实现。
2.具体主题角色:在具体主题内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个子类实现。
3.抽象观察者角色:为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。
4.具体观察者角色:该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体观察角色可以保存一个指向具体主题角色的引用。通常用一个子类实现。
实现自己的观察者模式:
使用示例:
观察者模式在Java语言中的地位极其重要,JDK也提供了对观察者模式的内置支持
Observable类:该类用于创建可以观测到你的程序中其他部分的子类。也就是上述所说的主题角色,也是被观察者。当这种子类的对象发生变化时,观测类被通知。观测类必须实现定义了update()方法的Observer接口,也就是观察者角色。当一个观测程序被通知到另一个被观测对象的改变时,update()方法被调用。
一个被观测的对象(主题角色)必须服从下面两个简单的规则:
1.如果它被改变了,必须调用setChanged()
2.当它准备通知观察者它的改变时,必须调用notifyObservers()方法。这会使得在观察者对象中update()方法的调用。
当对象在调用notifyObservers()方法之前,没有调用setChanged()方法,就不会有什么动作发生(查看源码可知原因)。在update()被调用之前,被观测对象必须调用setChanged()和notifyObservers()两种方法
如果changed(初始值为false)为false,那么直接返回,不会执行通知操作。所以需要改变changed的状态,则需要setChange()方法,将changed改为true。
应用:编写一个程序,声明一个类,该类继承自Observable(因此该类是个主题角色),有一个int类型的变量,初始值为10,编写一个for循环,将该数字每次递减1,一直到0为止,每次变化时,都将该数字传递给它的观察者,观测者会打印出该数字;第二个观察者在该数字变为I5之后开始打印该数字。
写个main方法用一下:
输出结果:
Watcher 1:10
Watcher 1:9
Watcher 1:8
Watcher 1:7
Watcher 1:6
Watcher 2:5
Watcher 1:5
Watcher 2:4
Watcher 1:4
Watcher 2:3
Watcher 1:3
Watcher 2:2
Watcher 1:2
Watcher 2:1
Watcher 1:1
Watcher 2:0
Watcher 1:0
从结果可以看出,观察者2只有在计数不大于5时才输出
其中,“自动调用”是不准确的,确切地说来还是按钮去调用了与之关联的处理器方法。
这其中,也涉及到了一种设计模式————观察者模式
观察者模式:一对多的依赖关系,多个观察者对象同时监听某一主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,让他们能够自动更新自己。
观察者模式的组成:
1.抽象主题角色(也就是被观察者):把所有观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类或接口来实现。
2.具体主题角色:在具体主题内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个子类实现。
3.抽象观察者角色:为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。
4.具体观察者角色:该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体观察角色可以保存一个指向具体主题角色的引用。通常用一个子类实现。
实现自己的观察者模式:
/** * 主题抽象角色:也称为被观察者 * addWatcher添加观察者 * removeWatcher删除观察者 * notifyWatcher通知观察者状态更新 */ public interface Watched { public void addWatcher(Watcher watcher); public void removeWatcher(Watcher watcher); public void notifyWatcher(String str); }
/** * 观察者抽象角色 * update方法用于更新状态,使得观察者状态与主题状态相协调 */ public interface Watcher { public void update(String str); }
/** * 具体主题角色:内部维护了对观察者角色的引用 * notifyWatcher实质上是通过调用所有观察者的update方法实现了观察者状态的更新 * 但对于用户来说,好像是主题发出状态改变,观察者“自动”更新状态 */ public class ConcreateWatched implements Watched { private List<Watcher> list = new ArrayList<Watcher>(); @Override public void addWatcher(Watcher watcher) { list.add(watcher); } @Override public void removeWatcher(Watcher watcher) { list.remove(watcher); } @Override public void notifyWatcher(String str) { //遍历所有的观察者引用,调用观察者中的方法 for(Watcher w : list){ w.update(str); } } }
/** *具体观察者角色 */ public class ConcreateWatcher implements Watcher { @Override public void update(String str) { System.out.println(str); } }
使用示例:
public class Client { public static void main(String[] args){ Watched girl = new ConcreateWatched(); Watcher boy1 = new ConcreateWatcher(); Watcher boy2 = new ConcreateWatcher(); Watcher boy3 = new ConcreateWatcher(); girl.addWatcher(boy1); girl.addWatcher(boy2); girl.addWatcher(boy3); girl.notifyWatcher("I am so happy."); girl.removeWatcher(boy1); girl.removeWatcher(boy2); girl.notifyWatcher("No happy"); } }
观察者模式在Java语言中的地位极其重要,JDK也提供了对观察者模式的内置支持
Observable类:该类用于创建可以观测到你的程序中其他部分的子类。也就是上述所说的主题角色,也是被观察者。当这种子类的对象发生变化时,观测类被通知。观测类必须实现定义了update()方法的Observer接口,也就是观察者角色。当一个观测程序被通知到另一个被观测对象的改变时,update()方法被调用。
一个被观测的对象(主题角色)必须服从下面两个简单的规则:
1.如果它被改变了,必须调用setChanged()
2.当它准备通知观察者它的改变时,必须调用notifyObservers()方法。这会使得在观察者对象中update()方法的调用。
当对象在调用notifyObservers()方法之前,没有调用setChanged()方法,就不会有什么动作发生(查看源码可知原因)。在update()被调用之前,被观测对象必须调用setChanged()和notifyObservers()两种方法
public void notifyObservers(Object arg) { /* * a temporary array buffer, used as a snapshot of the state of * current Observers. */ Object[] arrLocal; synchronized (this) { /* We don't want the Observer doing callbacks into * arbitrary code while holding its own Monitor. * The code where we extract each Observable from * the Vector and store the state of the Observer * needs synchronization, but notifying observers * does not (should not). The worst result of any * potential race-condition here is that: * 1) a newly-added Observer will miss a * notification in progress * 2) a recently unregistered Observer will be * wrongly notified when it doesn't care */ if (!changed) return; arrLocal = obs.toArray(); clearChanged(); } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); }
如果changed(初始值为false)为false,那么直接返回,不会执行通知操作。所以需要改变changed的状态,则需要setChange()方法,将changed改为true。
应用:编写一个程序,声明一个类,该类继承自Observable(因此该类是个主题角色),有一个int类型的变量,初始值为10,编写一个for循环,将该数字每次递减1,一直到0为止,每次变化时,都将该数字传递给它的观察者,观测者会打印出该数字;第二个观察者在该数字变为I5之后开始打印该数字。
/** * 被观测类(主题角色),需继承Observable */ public class MyTheme extends Observable { public void count(int num){ for (;num>=0;num--){ //使得changed属性为true,从而可以使得主题可以向观察者发送消息 this.setChanged(); //每一次技术都调用notifyObservers() this.notifyObservers(num); } } }
/** * 观察者1:打印主题角色的所有计数 */ public class Watcher1 implements Observer { @Override public void update(Observable o, Object arg) { System.out.println("Watcher1 "+arg); } }
/** * 观察者2:打印主题角色的计数,当且仅当技术不大于5 */ public class Watcher2 implements Observer { @Override public void update(Observable o, Object arg) { if(((Integer)arg).intValue() <= 5){ System.out.println("Watcher2:"+arg); } } }
写个main方法用一下:
public class Client { public static void main(String[] args){ MyTheme theme = new MyTheme(); Watcher1 obs1 = new Watcher1(); Watcher2 obs2 = new Watcher2(); theme.addObserver(obs1); theme.addObserver(obs2); theme.count(10); } }
输出结果:
Watcher 1:10
Watcher 1:9
Watcher 1:8
Watcher 1:7
Watcher 1:6
Watcher 2:5
Watcher 1:5
Watcher 2:4
Watcher 1:4
Watcher 2:3
Watcher 1:3
Watcher 2:2
Watcher 1:2
Watcher 2:1
Watcher 1:1
Watcher 2:0
Watcher 1:0
从结果可以看出,观察者2只有在计数不大于5时才输出
相关文章推荐
- 设计模式--观察者模式(行为类模式)
- 设计模式:观察者模式
- 设计模式20——行为型模式之观察者模式
- 23种设计模式(8):观察者模式
- Android开源—RXJava观察者设计模式
- 设计模式--观察者模式(五)
- ABAP与设计模式之观察者模式
- 设计模式:观察者模式(Observer)
- Android设计模式之观察者模式
- 设计模式-行为型之观察者模式
- Head First 设计模式——观察者模式(Observer Pattern)
- [C++设计模式]observer 观察者模式
- 设计模式C++实现(15)——观察者模式
- 设计模式学习笔记(二)之观察者模式(Observer)
- JAVA设计模式之观察者模式
- Java观察者设计模式
- Python设计模式——观察者模式
- 设计模式----行为型模式之观察者模式(Observer Pattern)
- 设计模式之观察者
- Head First 设计模式——观察者模式(Observer Pattern) 之二