欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java观察者设计模式(Observable和Observer)

程序员文章站 2024-03-07 17:59:15
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。 这个主题对象在状态上发生变化时,会通知所有观察者对象,让它们能够自动更新自己。 一、...

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。

这个主题对象在状态上发生变化时,会通知所有观察者对象,让它们能够自动更新自己。

一、观察者模式介绍

在java中通过observable类和observer接口实现了观察者模式。一个observer对象监视着一个observable对象的变化,当observable对象发生变化时,observer得到通知,就可以进行相应的工作。

如果画面a是显示数据库里面的数据,而画面b修改了数据库里面的数据,那么这时候画面a就要重新load。这时候就可以用到观察者模式

二、观察者模式实现方法

java.util.observable中有两个方法对observer特别重要

①setchanged()方法

/** 
* sets the changed flag for this {@code observable}. after calling 
* {@code setchanged()}, {@code haschanged()} will return {@code true}. 
*/ 
protected void setchanged() { 
changed = true; 
} 
②notifyobservers()方法 / notifyobservers(object data)方法
[java] view plaincopy
/** 
* if {@code haschanged()} returns {@code true}, calls the {@code update()} 
* method for every observer in the list of observers using null as the 
* argument. afterwards, calls {@code clearchanged()}. 
* <p> 
* equivalent to calling {@code notifyobservers(null)}. 
*/ 
public void notifyobservers() { 
notifyobservers(null); 
} 
/** 
* if {@code haschanged()} returns {@code true}, calls the {@code update()} 
* method for every observer in the list of observers using the specified 
* argument. afterwards calls {@code clearchanged()}. 
* 
* @param data 
* the argument passed to {@code update()}. 
*/ 
@suppresswarnings("unchecked") 
public void notifyobservers(object data) { 
int size = 0; 
observer[] arrays = null; 
synchronized (this) { 
if (haschanged()) { 
clearchanged(); 
size = observers.size(); 
arrays = new observer[size]; 
observers.toarray(arrays); 
} 
} 
if (arrays != null) { 
for (observer observer : arrays) { 
observer.update(this, data); 
} 
} 
} 

以上两个方法十分重要

setchanged()方法 ——

用来设置一个内部标志位注明数据发生了变化
notifyobservers()方法 / notifyobservers(object data)方法 ——
通知所有的observer数据发生了变化,这时所有的observer会自动调用复写好的update(observable observable, object data)方法来做一些处理(比如说画面数据的更新)。
我们可以看到通知observer有两个方法,一个无参,一个有参。那么这个参数有什么作用呢?
其中一个作用:现在我不想通知所有的observer,而只想其中一个指定的observer做一些处理,那么就可以传一个参数作为id,然后在所有的observer中判断,每个observer判断只有接收到底参数id是属于自己的才做一些处理。

当然参数还有其他作用,我只是举了个例子。

下面举个例子加以说明:

import java.util.observable; 
/** 
* 被观察者类 
*/ 
public class simpleobservable extends observable 
{ 
private int data = 0; 
public int getdata(){ 
return data; 
} 
public void setdata(int i){ 
if(this.data != i) { 
this.data = i; 
setchanged(); 
//只有在setchange()被调用后,notifyobservers()才会去调用update(),否则什么都不干。 
notifyobservers(); 
} 
} 
} 

上面这个类是一个被观察者类,它继承了observable类,表示这个类是可以被观察的。
然后在setdata()方法里面,也就是数据改变的地方,来调用observable类的setchanged()方法和notifyobservers()方法,表示数据已改变并通知所有的observer调用它们的update()方法做一些处理。

注意:只有在setchange()被调用后,notifyobservers()才会去调用update(),否则什么都不干。

/** 
* 观察者类 
*/ 
public class simpleobserver implements observer 
{ 
public simpleobserver(simpleobservable simpleobservable){ 
simpleobservable.addobserver(this ); 
} 

public void update(observable observable ,object data){ // data为任意对象,用于传递参数 
system.out.println(“data has changed to” + (simpleobservable)observable.getdata()); 
} 
} 

通过生成被观察者(simpleobservable类)的实例,来调用addobserver(this)方法让观察者(simpleobserver类)达到观察被观察者(simpleobservable类)的目的。
然后还要复写update()方法,做数据改变后的一些处理。

下面可以写一个简单的测试类来测试一下

public class simpletest 
{ 
public static void main(string[] args){ 
simpleobservable doc = new simpleobservable (); 
simpleobserver view = new simpleobserver (doc); 
doc.setdata(1); 
doc.setdata(2); 
doc.setdata(2); 
doc.setdata(3); 
} 
} 

运行结果如下

data has changed to 1
data has changed to 2 //第二次setdata(2)时由于没有setchange,所以update没被调用
data has changed to 3

下面介绍一个observable类的其他一些属性和方法

属性 ——

// observers是一个list,保存着所有要通知的observer。
list<observer> observers = new arraylist<observer>();
// changed是一个boolean型标志位,标志着数据是否改变了。
boolean changed = false;

方法 ——

// 添加一个observer到列表observers中 
public void addobserver(observer observer) { 
if (observer == null) { 
throw new nullpointerexception(); 
} 
synchronized (this) { 
if (!observers.contains(observer)) 
observers.add(observer); 
} 
} 
// 从列表observers中删除一个observer 
public synchronized void deleteobserver(observer observer) { 
observers.remove(observer); 
} 
// 清空列表observers 
public synchronized void deleteobservers() { 
observers.clear(); 
} 
// 返回列表observers中observer的个数 
public int countobservers() { 
return observers.size(); 
} 
// 重置数据改变标志位为未改变 
protected void clearchanged() { 
changed = false; 
} 
// 将数据改变标志位设置为改变 
protected void setchanged() { 
changed = true; 
} 
// 判断标志位的值 
public boolean haschanged() { 
return changed; 
} 
// 通知所有observer(无参) 
public void notifyobservers() { 
notifyobservers(null); 
} 
// 通知所有observer(有参) 
@suppresswarnings("unchecked") 
public void notifyobservers(object data) { 
int size = 0; 
observer[] arrays = null; 
synchronized (this) { 
if (haschanged()) { 
clearchanged(); 
size = observers.size(); 
arrays = new observer[size]; 
observers.toarray(arrays); 
} 
} 
if (arrays != null) { 
for (observer observer : arrays) { 
observer.update(this, data); 
} 
} 
} 

注意:在observer对象销毁前一定要用deleteobserver将其从列表中删除,也就是在ondestroy()方法中调用deleteobserver()方法。

不然因为还存在对象引用的关系,observer对象不会被垃圾收集,造成内存泄漏,并且已死的observer仍会被通知到,有可能造成意料外的错误,而且随着列表越来越大,notifyobservers操作也会越来越慢。

 观察者模式所涉及的角色有:

  ●  抽象主题(subject)角色:抽象主题角色把所有对观察者对象的引用保存在一个聚集(比如arraylist对象)里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,抽象主题角色又叫做抽象被观察者(observable)角色。

  ●  具体主题(concretesubject)角色:将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者(concrete observable)角色。

  ●  抽象观察者(observer)角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己,这个接口叫做更新接口。

  ●  具体观察者(concreteobserver)角色:存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态 像协调。如果需要,具体观察者角色可以保持一个指向具体主题对象的引用。