Observerパターン

Head First デザインパターンのメモ。

Observerパターン

オブジェクト間の1対多の依存関係を定義し、あるオブジェクトの状態が変化すると、
それに依存しているすべてのオブジェクトが自動的に通知され更新されるようにする。

新聞の定期購読

  • 発行者(Subject) = データを管理。データが変化するとObserverに通知。
  • 購読者(Observer) = Subjectを登録し、更新情報を受信する。

パターン定義

SubjectとObserverは一対多の関係。ObserverはSubjectに依存する。
ほとんどの実装方法は、SubjectとObjectのインターフェースを含む設計となる。
Subjectからデータを渡したり取得したりできる(プッシュとプル)。
(プルのほうが「適切」であると考えられている。)

疎結合

2つのオブジェクトが疎結合であると、お互いについてほとんど知る必要がなくなる。
SubjectはObserverがある特定のインターフェースを実装しているということのみ知っている。
新しいObserverをいつでも追加・削除できる。その時Subjectを変更する必要はない。
それぞれを独立して再利用でき、どちらかを変更しても他方に影響を与えない。

実装

気象観測所を実装。気象条件(気温、湿度、気圧)を監視し、三つの異なる要素を表示する場合。
データを渡すパターン(プッシュモデル)。

public interface Subject {
    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObservers();
}

// すべてのObserverが実装するインターフェース
public interface Observer {
  // 引数は気象情報が変化した際にSubjectから取得する状態値
    public void update(float temp, float humidity, float pressure);
}

// Subjectの実装 
public class WeatherData implements Subject {
    private ArrayList observers; // Observerを保持する配列
    private float temperature;
    private float humidity;
    private float pressure;
    
    public WeatherData() {
        observers = new ArrayList(); 
    }
    
    // Observerを登録する
    public void registerObserver(Observer o) {
        observers.add(o);
    }

    public void removeObserver() {
        int i = observers.indexOf(o);
        if (i >= 0) {
            observers.remove(i);
        }
    }

    public void notifyObservers() {
        for (int i = 0; 0 < observers.size(); i++) {
            Observer observer = (Observer)observers.get(i);
            observer.update(temperature, humidity, pressure);
        }
    }
    
    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        notifyObservers();
    }

    // 略
}

// 表示側(Observer)
public class CurrentConditionsDisplay implements Observer {
    private float temperature;
    private float humidity;
    private Subject weatherData;

    // WeatherDataオブジェクトに自身をObserverとして登録
    public CurrentConditionsDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }

    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        display();
    }

    public void display() {
        System.out.println("現在の気象状況:湿度" + temperature + "度 湿度" + humidity + "%")
    }
}

OOの原則

相互にやり取りするオブジェクト間には、疎結合設計を使用するようにする。


Strategyパターン
Head First デザインパターンを読む