ゲームが作れるようになるまでがんばる日記

ゲーム制作のことを中心にゲームに関することを書いています

Observer

観察者という意味。観察対象の状態が変化したら、観察者に対して通知する。
Model View Controller(MVC)のモデルとビューの関係といったほうが分かりやすいかも。内部データを持つ部分(モデル)と表示する部分(ビュー)を分け、モデルの内部データが更新されたら、ビューに通知して表示を更新する。Observerパターンはその関係と同じ。
RPGゲームでダメージを受けたときに、そのダメージの値をメッセージでログに出力するのと画面に描画する場合を考えてみた。

// Observerの抽象クラス Observer.java
public interface Observer {
    public abstract void update(Parameter parameter);
}
// パラメータを表す抽象クラス Parameter.java
import java.util.Vector;
import java.util.Iterator;

public abstract class Parameter {
    private Vector observers = new Vector();
    // Observerの追加
    public void addObserver(Observer observer) {
        observers.add(observer);
    }
    // Observerの削除
    public void deleteObserver(Observer observer) {
        observers.remove(observer);
    }
    // Observerへ通知
    public void notifyObservers() {
        Iterator it = observers.iterator();
        while(it.hasNext()) {
            Observer o = (Observer)it.next();
            o.update(this);
        }
    }
    // 値の取得
    public abstract int getNumber();
    // 値のセット
    public abstract void setNumber(int number);
}
// ダメージを表現するクラス Damage.java
public class Damage extends Parameter {
    private int damage;
    public int getNumber() {
        return damage;
    }
    public void setNumber(int number) {
        damage = number;
        notifyObservers();
    }
}
// パラメータをログに表示するObserver LogObserver.java
public class LogObserver implements Observer {
    public void update(Parameter parameter) {
        // ここでログに表示
        System.out.println("Log: Damage = " + parameter.getNumber());
    }
}
// パラメータを画面に描画するObserver ScreenObserver.java
public class ScreenObserver implements Observer {
    public void update(Parameter parameter) {
        // ここで画面に描画
        System.out.println("Screen: Damage = " + parameter.getNumber());
    }
}
// テストメイン
public class Main {
    public static void main(String[] args) {
        Damage damage = new Damage();
        Observer log = new LogObserver();
        Observer screen = new ScreenObserver();
        damage.addObserver(log);
        damage.addObserver(screen);

        damage.setNumber(100);
        damage.setNumber(999);
    }
}

オプションによって画面だけに描画とか、ログにだけ出力とか選んだ場合は、それにあわせてaddObserver()やdeleteObserver()でObserverを追加削除すればよい。
で、ここまで試しに作ってみたけど、たかがダメージ1つ表示するのに大げさだ。実際に作るときはこうはしないだろう。あくまでObserverを理解するためのサンプルということで。


参考文献:Java言語で学ぶデザインパターン入門
参考:
ギコ猫とObserverパターン
Observer パターン - Wikipedia