はじめに
こちらの記事はGoFのデザインパターンに基づいたObserverパターンについての解説になります。
Observerパターンを調べたけどイマイチよく分からんという方のために
具体的な実装例からイメージを掴めてもらえるような記事にしました。
※Observerの一般的な説明はこちら
<参考>
Java言語で学ぶデザインパターン入門
Observerパターンとは
Observerとは、「観察者」という意味です。
すなわち、観察対象の状態が変化すると、観察者に対して通知がされます。
Observerパターンは、状態変化に応じた処理を記述するときに有効です。
サンプルプログラムの構成
クラス名 | 説明 |
---|---|
Observer | 観察者を表すインターフェース |
NumberGenerator | 数を生成するオブジェクトを表す抽象クラス |
RandomNumberGenerator | ランダムに数を生成するクラス |
DigitObserver | 数字で数を表示するクラス |
GraphObserver | 簡易グラフで数を表示するクラス |
Main | 動作テスト用のクラス |
Observerインターフェース
「観察者」を表現するインターフェース
public interface Observer {
public abstract void update(NumberGenerator generator);
}
・updateメソッドはNumberGeneretorクラスで呼び出される
NumberGeneratorクラス
数を生成するオブジェクトを表す抽象クラス
import java.util.ArrayList;
import java.util.Iterator;
public abstract class NumberGenerator {
private ArrayList observers = new ArrayList();
// Observerを追加する
public void addObserver(Observer observer) {
observers.add(observer);
}
// Observerを削除する
public void deleteObserver(Observer observer) {
observers.remove(observer);
}
// Observer全員に対して「私の内容が更新されたので、あなたの表示を更新して下さい」と伝える
public void notifyObserver() {
Iterator it = observers.iterator();
while(it.hasNext()) {
Observer o = (Observer)it.next();
o.update(this);
}
}
// 数を取得する
public abstract int getNumber();
// 数を生成する
public abstract void execute();
}
・Observerへ通知するnotifyObserver()の中でupdateメソッドを呼ぶことで、
Observer全員に対して表示を更新するように伝えている
RandomNumberGeneratorクラス
NumberGeneratorのサブクラスで乱数を生成するクラス
import java.util.Random;
public class RandomNumberGenerator extends NumberGenerator {
// 乱数を発生させる
private Random random = new Random();
// 現在の数
private int number;
// 数を取得する
public int getNumber() {
return number;
}
public void execute() {
for (int i = 0; i < 20; i++) {
number = random.nextInt(50);
notifyObserver();
}
}
}
・executeメソッドは乱数を20個生成し、
生成する毎にnotifyObserver()を使って、観察者に通知する。
DigitObserverクラス
観察した数を数字で表示するクラス
Observerインターフェースを実装
public class DigitObserver implements Observer{
public void update(NumberGenerator generator) {
System.out.println("DigitObserver:" + generator.getNumber());
// sleepは表示を見やすくするためにつけている
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
}
}
}
・updateメソッドを実装
GraphObserverクラス
観察した数を*****のような表現で表示をするクラス
Observerインターフェースを実装
public class GraphObserver implements Observer{
public void update(NumberGenerator generator) {
System.out.print("GraphObserver:");
int count = generator.getNumber();
for (int i = 0; i < count; i++) {
System.out.print("*");
}
System.out.println("");
// sleepは表示を見やすくするためにつけている
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
・updateメソッドを実装
Mainクラス
動作テスト用のクラス
public class Main {
public static void main(String[] args) {
NumberGenerator generator = new RandomNumberGenerator() ;
Observer observer1 = new DigitObserver();
Observer observer2 = new GraphObserver();
generator.addObserver(observer1);
generator.addObserver(observer2);
generator.execute();
}
}
実行結果
DigitObserver:7
GraphObserver:*******
DigitObserver:1
GraphObserver:*
DigitObserver:9
GraphObserver:*********
DigitObserver:3
GraphObserver:***
DigitObserver:12
GraphObserver:************
(以下略)
プログラムの解説
状態を持っているRandomNumberGeneratorクラスがあって、
乱数が生成されると、状態が変わったということでnotifyObserver()を呼び出します。
norifyObserver()が呼び出され、各Observerそれぞれが持つ実装されたupdateメソッドが実行されます。
「観察」ではなく「通知」
Observerは観察者という意味なので、変更を「観察」していると考えられますが、
実際の動きを見ると能動的に観察しているわけではなく、
状態が変わったと「通知」されるのを受動的に待っているような作りとなっています。
開発をしているとよく遭遇するデザインパターンなので、
具体的な実装例からなんとなくでもイメージを掴めてもらえると嬉しいです。