java观察者模式_Java 观察者模式

在阎宏博士的《JAVA与模式》一书中开头是这样描述观察者(Observer)模式的:观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

观察者模式的结构

一个软件系统通常要求在某个对象的状态变化时,其他的某些对象随之变化。观察者模式是满足这一要求的所有方案中最好的一种。结构图如下:

9e0ea0925e7235a2b43210c4c5572c9f.png

涉及的角色:

抽象主题(Subject)角色:抽象主题角色又叫做抽象被观察者(Observable)角色。定义一个可以增加和删除观察者对象的接口,每个主题把所有观察者对象的引用保存在一个集合(例如ArrayList)里面。

具体主题(ConcreteSubject)角色:具体主题角色又叫做具体被观察者(Concrete Observable)角色。在具体主题的状态变化时,给所有登记过的观察者发出通知。

抽象观察者(Observer)角色:为所有的具体观察者定义一个更新接口,收到主题的通知时更新具体观察者。

具体观察者(ConcreteObserver)角色:存储与主题状态适应的状态,实现了抽象观察者角色的更新接口。

抽象主题角色类

1 public abstract classSubject {2 /**

3 * 用来保存注册的观察者对象4 */

5 private List list = new ArrayList();6 /**

7 * 注册观察者对象8 *@paramobserver 观察者对象9 */

10 public voidattach(Observer observer){11

12 list.add(observer);13 System.out.println("Attached an observer");14 }15 /**

16 * 删除观察者对象17 *@paramobserver 观察者对象18 */

19 public voiddetach(Observer observer){20

21 list.remove(observer);22 }23 /**

24 * 通知所有注册的观察者对象25 */

26 public voidnodifyObservers(String newState){27

28 for(Observer observer : list){29 observer.update(newState);30 }31 }32 }

具体主题角色类

1 public class ConcreteSubject extendsSubject{2

3 privateString state;4

5 publicString getState() {6 returnstate;7 }8

9 public voidchange(String newState){10 state =newState;11 System.out.println("主题状态为:" +state);12 //状态发生改变,通知各个观察者

13 this.nodifyObservers(state);14 }15 }

抽象观察者角色类

1 public interfaceObserver {2 /**

3 * 更新接口4 *@paramstate 更新的状态5 */

6 public voidupdate(String state);7 }

具体观察者角色类

1 public class ConcreteObserver implementsObserver {2 //观察者的状态

3 privateString observerState;4

5 @Override6 public voidupdate(String state) {7 /**

8 * 更新观察者的状态,使其与目标的状态保持一致9 */

10 observerState =state;11 System.out.println("状态为:"+observerState);12 }13

14 }

客户端类

1 public classClient {2

3 public static voidmain(String[] args) {4 //创建主题对象

5 ConcreteSubject subject = newConcreteSubject();6 //创建观察者对象

7 Observer observer = newConcreteObserver();8 //将观察者对象登记到主题对象上

9 subject.attach(observer);10 //改变主题对象的状态

11 subject.change("new state");12 }13

14 }

结果:

662ebe29261b978f07735d435b5a5bfa.png

客户端先创建具体主题类的实例和一个观察者对象。然后,它调用主题对象的attach方法,将观察者对象登记到主题对象上,即把它加入到主题对象的集合中。客户端调用主题对象的change方法后改变了主题对象的状态。主题对象在状态变化时,调用父类的notifyObservers方法,通知所有登记过的观察者对象,更新它们的状态。

推模型和拉模型

观察者模式分为推模型和拉模型两种方式。

推模型:不管观察者对象是否需要,主题对象都会向观察者对象推送主题的详细信息。

拉模型: 主题对象在通知观察者对象时,只传递少量信息。如果观察者对象需要更具体的信息,观察者对象需要主动向主题对象获取,相当于观察者对象从主题对象中拉数据。通过update方法把主题对象传递给观察者对象,通过主题对象获取信息。

前面的例子是推模型,下面给出一个拉模型的实例:

拉模型的抽象观察者类

1 public interfaceObserver {2 /**

3 * 更新接口4 *@paramsubject 传入主题对象,方面获取相应的主题对象的状态5 */

6 public voidupdate(Subject subject);7 }

拉模型的具体观察者类

1 public class ConcreteObserver implementsObserver {2 //观察者的状态

3 privateString observerState;4

5 @Override6 public voidupdate(Subject subject) {7 /**

8 * 更新观察者的状态,使其与目标的状态保持一致9 */

10 observerState =((ConcreteSubject)subject).getState();11 System.out.println("观察者状态为:"+observerState);12 }13

14 }

拉模型的抽象主题类

1 public abstract classSubject {2 /**

3 * 用来保存注册的观察者对象4 */

5 private List list = new ArrayList();6 /**

7 * 注册观察者对象8 *@paramobserver 观察者对象9 */

10 public voidattach(Observer observer){11

12 list.add(observer);13 System.out.println("Attached an observer");14 }15 /**

16 * 删除观察者对象17 *@paramobserver 观察者对象18 */

19 public voiddetach(Observer observer){20

21 list.remove(observer);22 }23 /**

24 * 通知所有注册的观察者对象25 */

26 public voidnodifyObservers(){27

28 for(Observer observer : list){29 observer.update(this);30 }31 }32 }

拉模型的具体主题类

1 public class ConcreteSubject extendsSubject{2

3 privateString state;4

5 publicString getState() {6 returnstate;7 }8

9 public voidchange(String newState){10 state =newState;11 System.out.println("主题状态为:" +state);12 //状态发生改变,通知各个观察者

13 this.nodifyObservers();14 }15 }

两种模式的比较

推模型是假设主题对象知道观察者对象需要的数据;而拉模型是主题对象不知道观察者对象需要什么数据。

推模型可能会使观察者对象难以复用,因为观察者对象的update方法是按需要定义形参,可能无法兼顾没有考虑到的使用情况。当新情况出现时,就可能需要提供新的update方法,或者重新实现观察者类;而拉模型不会出现这种情况,因为观察者对象的update方法的形参是主题对象,通过主题对象可以获取所有信息。

Java对观察者模式的支持

java.util库提供了一个Observer接口和一个Observable类。

Observer接口

只定义了一个update方法。当被观察者对象的状态变化时,被观察者对象的notifyObservers方法就会调用该方法。

1 public interfaceObserver {2 voidupdate(Observable o, Object arg);3 }

Observable类

被观察者类相当于抽象主题类,是java.util.Observable类的子类。有两个方法对Observable的子类来说很重要:一个是setChanged方法,被调用后会设置一个标记变量,代表被观察者对象的状态变化了。第二个是notifyObservers方法,被调用时会调用所有登记过的观察者对象的update方法,更新观察者对象。

1 public classObservable {2 private boolean changed = false;3 privateVector obs;4

5 /**Construct an Observable with zero Observers.*/

6

7 publicObservable() {8 obs = newVector();9 }10

11 /**

12 * 将一个观察者添加到观察者聚集上面13 */

14 public synchronized voidaddObserver(Observer o) {15 if (o == null)16 throw newNullPointerException();17 if (!obs.contains(o)) {18 obs.addElement(o);19 }20 }21

22 /**

23 * 将一个观察者从观察者聚集上删除24 */

25 public synchronized voiddeleteObserver(Observer o) {26 obs.removeElement(o);27 }28

29 public voidnotifyObservers() {30 notifyObservers(null);31 }32

33 /**

34 * 如果本对象有变化(那时hasChanged 方法会返回true)35 * 调用本方法通知所有登记的观察者,即调用它们的update()方法36 * 传入this和arg作为参数37 */

38 public voidnotifyObservers(Object arg) {39

40 Object[] arrLocal;41

42 synchronized (this) {43

44 if (!changed)45 return;46 arrLocal =obs.toArray();47 clearChanged();48 }49

50 for (int i = arrLocal.length-1; i>=0; i--)51 ((Observer)arrLocal[i]).update(this, arg);52 }53

54 /**

55 * 将观察者聚集清空56 */

57 public synchronized voiddeleteObservers() {58 obs.removeAllElements();59 }60

61 /**

62 * 将“已变化”设置为true63 */

64 protected synchronized voidsetChanged() {65 changed = true;66 }67

68 /**

69 * 将“已变化”重置为false70 */

71 protected synchronized voidclearChanged() {72 changed = false;73 }74

75 /**

76 * 检测本对象是否已变化77 */

78 public synchronized booleanhasChanged() {79 returnchanged;80 }81

82 /**

83 * Returns the number of observers of this Observable object.84 *85 *@returnthe number of observers of this object.86 */

87 public synchronized intcountObservers() {88 returnobs.size();89 }90 }

如何使用?

被观察者类Watched

1 public class Watched extendsObservable{2

3 private String data = "";4

5 publicString getData() {6 returndata;7 }8

9 public voidsetData(String data) {10

11 if(!this.data.equals(data)){12 this.data =data;13 setChanged();14 }15 notifyObservers();16 }17

18

19 }

观察者类Watcher

1 public class Watcher implementsObserver{2

3 publicWatcher(Observable o){4 o.addObserver(this);5 }6

7 @Override8 public voidupdate(Observable o, Object arg) {9

10 System.out.println("状态发生改变:" +((Watched)o).getData());11 }12

13 }

测试类Test

public classTest {public static voidmain(String[] args) {//创建被观察者对象

Watched watched = newWatched();//创建观察者对象,并将被观察者对象登记

Observer watcher = newWatcher(watched);//给被观察者状态赋值

watched.setData("start");

watched.setData("run");

watched.setData("stop");

}

}

先创建Watched和Watcher对象。在创建Watcher对象时,将Watched对象作为参数传入。然后Watched对象调用setData方法,更改Watched对象的状态。Watched对象通知登记过的Watcher对象,调用它的update方法。

参考资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值