Javaオブザーバ設計モード(ObservableとObserver)
このトピックオブジェクトは、ステータスが変化すると、すべてのオブジェクトに自動的に更新できるように通知されます.
一、観察者モードの紹介
JavaではObservableクラスとObserverインタフェースによりオブザーバモードを実現した.1つのObserverオブジェクトが1つのObservableオブジェクトの変化を監視しており、Observableオブジェクトが変化した場合、Observerは通知を受け、対応する作業を行うことができる.
画面Aがデータベース内のデータを表示し、画面Bがデータベース内のデータを修正した場合、画面Aは再びロードされます.観察者モードを使うことができます
二、観察者モードの実現方法
JAva.util.ObservableにはObserverにとって特に重要な2つの方法があります
①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()}.
*
* 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);
}
}
}
以上の2つの方法は非常に重要である.
setChanged()メソッド――
内部フラグビット指定データが変化したことを示すnotifyObservers()メソッド/notifyObservers(Object data)メソッドを設定するために使用されます.すべてのObserverデータが変化したことを通知します.この場合、すべてのObserverは、複写されたupdate(Observable observable,Object data)メソッドを自動的に呼び出して、画面データの更新などの処理を行います.Observerに通知するには2つの方法があり,1つは無参で,1つは有参であることがわかる.では、このパラメータはどのような役割を果たしていますか?1つの役割:今私はすべてのObserverに通知したくなくて、その中の1つの指定したObserverだけがいくつかの処理をしたいと思って、それでは1つのパラメータを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//2回目のsetData(2)の場合はsetChangeがないためupdateはData has changed to 3を呼び出さなかった
Observableクラスの他の属性と方法について説明します.
属性―――
//observersは、通知するobserverをすべて保存するリストです.List observers = new ArrayList(); //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)ロール:抽象トピックロールは、すべてのオブジェクトに対する参照を1つの集計(例えば、ArrayListオブジェクト)に保存し、各トピックには任意の数のオブジェクトが存在してもよい.抽象トピックは、オブザーバーオブジェクトを追加および削除するインタフェースを提供します.抽象トピックロールは、オブザーバー(Observable)ロールとも呼ばれます.
●特定テーマ(ConcreteSubject)キャラクター:関連状態を特定の観察者オブジェクトに保存する;特定のトピックの内部状態が変化した場合,登録されたすべての観察者に通知する.具体的なテーマキャラクタは、具体的なオブジェクトキャラクタとも呼ばれます.
●抽象オブザーバー(Observer)ロール:すべての特定のオブザーバーにインタフェースを定義し、トピックの通知を受けたときに自分を更新します.このインタフェースを更新インタフェースと呼びます.
●特定オブザーバー(ConcreteObserver)ロール:トピックの状態と適切な状態を格納します.特定のオブザーバーキャラクタは、抽象オブザーバーキャラクタが要求する更新インタフェースを実現し、自身の状態とトピックの状態像を調和させる.必要に応じて、特定のオブザーバーキャラクタは、特定のトピックオブジェクトへの参照を保持できます.