●目的
あるオブジェクトの状態が変化したことをチェックしたい。
●よくある問題点
あるオブジェクト1があるとして、そのオブジェクト1の状態が変化したときに、別のオブジェクト2でそのオブジェクト1の状態の変化に合わせて、何かをやりたいというケースがあると思います。
オブジェクト1は自分の状態変化によってオブジェクト2が何をやりたいのかは知らないので、オブジェクト1と2の関係は連携とは言いにくい一方的なものとなります。この代表的な例がマウスイベントの通知になると思います。
このようにオブジェクトに通知機能をもたせたり、また前述したようなオブジェクト1と2が「1:n」や「n:1」になったりする場合(オブジェクト2が通知するオブジェクト1を複数持つ構成になったり、オブジェクト1の通知相手が複数になる構成になったりする場合)にも対処できるようにするためには、どのようにしたらよいのかを次の「解決方法」でみていきたいと思います。
●解決方法
前述した例で考えると、オブジェクト1は状態の変化を観察される側になり、オブジェクト2はオブジェクト1の状態変化を観察する側(=オブザーバー)になります。
まず、監視するオブジェクトが実装するためのインターフェース「InterfaceObserver」を用意します。今回はこのインタフェースを実装するクラスObserverAとObserverBを用意します。
また、監視される側のクラスは「MyClass」とします。MyClassは複数のオブザーバーが登録できるように内部にVectorオブジェクトを用意し、addObserverメソッドを用意します。(※直感的に複数の値を次々と追加できることがわかるよう、setではなくadd〜というメソッドのネーミングにしています。)
MyClassは、このVectorに登録されているオブジェクトの数だけ、for文のなかでオブザーバーとなっているオブジェクトに通知を行っています。
以上が、Observerパターンになります。
●図解
●サンプルコード
・InterfaceObserver.java(インターフェース)
public interface InterfaceObserver{
void done (int updateValue);
}
・ObserverA.java(インタフェース”InterfaceObserver”を実装)
public class ObserverA implements InterfaceObserver {
@Override
public void done(int updateValue) {
System.out.println(“MyObserverA (Updated : ” + updateValue + “)”);
}
}
・ObserverB.java(インタフェース”InterfaceObserver”を実装)
public class ObserverB implements InterfaceObserver {
@Override
public void done(int updateValue) {
System.out.println(“MyObserverB (Updated : ” + updateValue + “)”);
}
}
・MyClass.java(状態変化を通知するクラス)
import java.util.Vector;
class MyClass {
int value = 0;
Vector observers = new Vector();
void addObserver(InterfaceObserver observer){
observers.add(observer);
}
void doIt(){
value++;
//オブザーバーの全オブジェクトに通知
for(int i = 0; i < observers.size(); i++){
InterfaceObserver observer = (InterfaceObserver)observers.get(i);
observer.done(value);
}
}
}
・Main.java(クライアント側プログラム)
class Main {
public static void main(String[] args) {
MyClass myclass = new MyClass();
//監視する側のオブジェクトを生成
ObserverA observerA = new ObserverA();
ObserverB observerB = new ObserverB();
//myclassにオブザーバーを登録
myclass.addObserver(observerA);
myclass.addObserver(observerB);
//myclassで状態変化を3回実行させてみる(MyClassのvalueに++)
myclass.doIt();
myclass.doIt();
myclass.doIt();
}
}
●注意
Observerパターンには、注意点があります。
それは、状態変化を監視するオブザーバーのオブジェクト間に関連がある場合です。なぜこれが問題になるかというと、Observerパターンではオブザーバーに通知する順序までは明確にされていないためです。どのオブザーバーが先に通知を受け取るかによって、動作が変わってしまうことに注意しなければなりません。
また、監視対象となっているオブジェクトにも強制的に状態変化を発生させるようなこともやらない方がよいと思います。もし、そのオブジェクトに他にオブザーバーがいるとそのオブジェクトに影響が出てしまいます。