【Java】Observer(オブザーバ)パターン

徒然草2.0

※個人的な学習メモです。

Observerパターンは、知っていると非常に便利なデザインパターンです。

解説

Observer(オブザーバー)とは観察者という意味です。

観察される、とあるオブジェクトをここではSubject(サブジェクト・観察される側)とすれば、Subjectに変化があった場合にSubjectに依存するオブジェクトに通知を行う仕組みだそうです。

画面などの操作でイベントを受取り画面を更新し直したり、外部のモジュールなりシステムへ通知したりする用途で使われます。

※Publish-Subscribeパターン(発行-購読パターン)と呼ばれることもあります。

実際のコード例(Java)

// Observer(通知される側)
interface Observer {
    void update(String msg);
}

// Subject(通知する側)

class Subject {
    private List<Observer> observers = new ArrayList<>();

    void add(Observer o) { observers.add(o); }

    void notifyAll(String msg) {
        for (Observer o : observers) o.update(msg);
    }
}

// 具体的なObserver
class User implements Observer {
    private String name;
    User(String name) { this.name = name; }

    public void update(String msg) {
        System.out.println(name + " received: " + msg);
    }
}

// 実行例
public class Main {
    public static void main(String[] args) {
        Subject subject = new Subject();

        subject.add(new User("田中"));
        subject.add(new User("佐藤"));

        subject.notifyAll("イベント発生!");
    }
}

コードの説明

SubjectはObserverを管理するリストを保持しており、Subjectの状態が変化したときにリスト内のObserverに通知を行う。

Observerが増加する条件は「通知を受け取る条件が増えた時」であり、新聞の購読に例えるならば「新しい新聞を受け取る時」である。逆にObserverが減少する条件は「通知を受け取る条件が減った時」であり「新聞の契約を1つ減らした時」である。

つまり、Subjectに登録されているすべてのObserverに一斉に通知が送信されます。Observerの先には外部モジュールなり外部システムとの通信処理があり、メール通知だったりSMS通知だったりするのかもしれません。

サンプルコードでは、田中さんや佐藤さんに一斉に”イベント発生”の通知を行っています。

疑問:なぜSubject内部にObserverがあるんだろう?

ここで疑問がでてきます。

Subject内部にObserverが在るのは、現実世界のモデリングという意味では変じゃないですか?(外部在るものを呼び出すようにしてはいけないのですか?)

結論から言えば、、、Observerが格納されるリストはObserverそのものではなく、Observerインスタンスへの参照に過ぎない。Subjectを新聞社だとすると、Observerリストは購読者の名簿であり、Observerの実体は外部に在る⋯ということになるので「ObserverはSubjectの外部に在るべき」という思想はObserverパターンで問題なく実現ができていることになる。

結論:Subject内にはObserverの参照があるのみ。実際にはObserverは外部にあると考えてよい。

疑問:StrategyパターンとObserverパターンって似てません?

結論から言えば非常に似ているが違う点もある。

StrategyもObserverも共通のインターフェースを持っており、異なる振る舞いを実装できるようにしている。各インスタンスの実装はカプセル化されており、メタクラスからは見えない(Strategyの場合はContext、Observerの場合はSubjectが、メタクラスにあたる)。

最も大きく違うのは目的で、Strategyパターンは差し替え可能な処理/アルゴリズムを個々に柔軟に切り替えることにあり(つまりメタクラスと1対1の関係になる)、Observerパターンは複数のObserverに一斉通知を行う(つまりメタクラスと1対多の関係になる)。

徒然草2.0
スポンサーリンク
シェアする
gomiryoをフォローする
ごみぶろぐ

コメント

タイトルとURLをコピーしました