Java观察者设计模式(Observable和Observer)
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。
这个主题对象在状态上发生变化时,会通知所有观察者对象,让它们能够自动更新自己。
一、观察者模式介绍
在Java中通过Observable类和Observer接口实现了观察者模式。一个Observer对象监视着一个Observable对象的变化,当Observable对象发生变化时,Observer得到通知,就可以进行相应的工作。
如果画面A是显示数据库里面的数据,而画面B修改了数据库里面的数据,那么这时候画面A就要重新Load。这时候就可以用到观察者模式
二、观察者模式实现方法
java.util.Observable中有两个方法对Observer特别重要
①setChanged()方法
/** *Setsthechangedflagforthis{@codeObservable}.Aftercalling *{@codesetChanged()},{@codehasChanged()}willreturn{@codetrue}. */ protectedvoidsetChanged(){ changed=true; } ②notifyObservers()方法/notifyObservers(Objectdata)方法 [java]viewplaincopy /** *If{@codehasChanged()}returns{@codetrue},callsthe{@codeupdate()} *methodforeveryobserverinthelistofobserversusingnullasthe *argument.Afterwards,calls{@codeclearChanged()}. *<p> *Equivalenttocalling{@codenotifyObservers(null)}. */ publicvoidnotifyObservers(){ notifyObservers(null); } /** *If{@codehasChanged()}returns{@codetrue},callsthe{@codeupdate()} *methodforeveryObserverinthelistofobserversusingthespecified *argument.Afterwardscalls{@codeclearChanged()}. * *@paramdata *theargumentpassedto{@codeupdate()}. */ @SuppressWarnings("unchecked") publicvoidnotifyObservers(Objectdata){ intsize=0; Observer[]arrays=null; synchronized(this){ if(hasChanged()){ clearChanged(); size=observers.size(); arrays=newObserver[size]; observers.toArray(arrays); } } if(arrays!=null){ for(Observerobserver:arrays){ observer.update(this,data); } } }
以上两个方法十分重要
setChanged()方法——
用来设置一个内部标志位注明数据发生了变化
notifyObservers()方法/notifyObservers(Objectdata)方法——
通知所有的Observer数据发生了变化,这时所有的Observer会自动调用复写好的update(Observableobservable,Objectdata)方法来做一些处理(比如说画面数据的更新)。
我们可以看到通知Observer有两个方法,一个无参,一个有参。那么这个参数有什么作用呢?
其中一个作用:现在我不想通知所有的Observer,而只想其中一个指定的Observer做一些处理,那么就可以传一个参数作为ID,然后在所有的Observer中判断,每个Observer判断只有接收到底参数ID是属于自己的才做一些处理。
当然参数还有其他作用,我只是举了个例子。
下面举个例子加以说明:
importjava.util.Observable; /** *被观察者类 */ publicclassSimpleObservableextendsObservable { privateintdata=0; publicintgetData(){ returndata; } publicvoidsetData(inti){ if(this.data!=i){ this.data=i; setChanged(); //只有在setChange()被调用后,notifyObservers()才会去调用update(),否则什么都不干。 notifyObservers(); } } }
上面这个类是一个被观察者类,它继承了Observable类,表示这个类是可以被观察的。
然后在setData()方法里面,也就是数据改变的地方,来调用Observable类的setChanged()方法和notifyObservers()方法,表示数据已改变并通知所有的Observer调用它们的update()方法做一些处理。
注意:只有在setChange()被调用后,notifyObservers()才会去调用update(),否则什么都不干。
/** *观察者类 */ publicclassSimpleObserverimplementsObserver { publicSimpleObserver(SimpleObservablesimpleObservable){ simpleObservable.addObserver(this); } publicvoidupdate(Observableobservable,Objectdata){//data为任意对象,用于传递参数 System.out.println(“Datahaschangedto”+(SimpleObservable)observable.getData()); } }
通过生成被观察者(SimpleObservable类)的实例,来调用addObserver(this)方法让观察者(SimpleObserver类)达到观察被观察者(SimpleObservable类)的目的。
然后还要复写update()方法,做数据改变后的一些处理。
下面可以写一个简单的测试类来测试一下
publicclassSimpleTest { publicstaticvoidmain(String[]args){ SimpleObservabledoc=newSimpleObservable(); SimpleObserverview=newSimpleObserver(doc); doc.setData(1); doc.setData(2); doc.setData(2); doc.setData(3); } }
运行结果如下
Datahaschangedto1
Datahaschangedto2//第二次setData(2)时由于没有setChange,所以update没被调用
Datahaschangedto3
下面介绍一个Observable类的其他一些属性和方法
属性——
//observers是一个List,保存着所有要通知的observer。
List<Observer>observers=newArrayList<Observer>();
//changed是一个boolean型标志位,标志着数据是否改变了。
booleanchanged=false;
方法——
//添加一个Observer到列表observers中 publicvoidaddObserver(Observerobserver){ if(observer==null){ thrownewNullPointerException(); } synchronized(this){ if(!observers.contains(observer)) observers.add(observer); } } //从列表observers中删除一个observer publicsynchronizedvoiddeleteObserver(Observerobserver){ observers.remove(observer); } //清空列表observers publicsynchronizedvoiddeleteObservers(){ observers.clear(); } //返回列表observers中observer的个数 publicintcountObservers(){ returnobservers.size(); } //重置数据改变标志位为未改变 protectedvoidclearChanged(){ changed=false; } //将数据改变标志位设置为改变 protectedvoidsetChanged(){ changed=true; } //判断标志位的值 publicbooleanhasChanged(){ returnchanged; } //通知所有observer(无参) publicvoidnotifyObservers(){ notifyObservers(null); } //通知所有observer(有参) @SuppressWarnings("unchecked") publicvoidnotifyObservers(Objectdata){ intsize=0; Observer[]arrays=null; synchronized(this){ if(hasChanged()){ clearChanged(); size=observers.size(); arrays=newObserver[size]; observers.toArray(arrays); } } if(arrays!=null){ for(Observerobserver:arrays){ observer.update(this,data); } } }
注意:在Observer对象销毁前一定要用deleteObserver将其从列表中删除,也就是在onDestroy()方法中调用deleteObserver()方法。
不然因为还存在对象引用的关系,Observer对象不会被垃圾收集,造成内存泄漏,并且已死的Observer仍会被通知到,有可能造成意料外的错误,而且随着列表越来越大,notifyObservers操作也会越来越慢。
观察者模式所涉及的角色有:
●抽象主题(Subject)角色:抽象主题角色把所有对观察者对象的引用保存在一个聚集(比如ArrayList对象)里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,抽象主题角色又叫做抽象被观察者(Observable)角色。
●具体主题(ConcreteSubject)角色:将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者(ConcreteObservable)角色。
●抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己,这个接口叫做更新接口。
●具体观察者(ConcreteObserver)角色:存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态像协调。如果需要,具体观察者角色可以保持一个指向具体主题对象的引用。