LoginSignup
1
2

デザインパターン Observerパターン

Last updated at Posted at 2023-10-06

Observerパターン

変化するデータや状態に関心を持つオブザーバ(観察者:Observer)と、その変化を通知するサブジェクト(観察対象:Subject)から構成される。

一対多の依存関係を定義し、あるオブジェクト(サブジェクト)の状態が変化すると、それに依存する複数の他のオブジェクト(オブザーバ)に自動的に通知される。

サブジェクト(Subject)

観察(Observe)の対象となる情報。

状態が変化する

観察対象となるデータの唯一の所持者であり、観察対象に何らかの変更があった場合、オブザーバに対してその変更を通知する

また、オブザーバを管理する(オブザーバの新規登録や、オブザーバの解除)役割も併せ持つ。

サブジェクトがオブザーバについて知っているのは、Observerインターフェースを実装しているということだけ。通知した情報がどのように利用されるのかなどは一切知らない(疎結合の関係)。

<<学習memo:発行者(Publisher)が管理している対象をサブジェクト(Subject)と言っているのかと思っていましたが、サブジェクト自身が発行者であるという理解の方が、定義的には正しいのかもしれません。または、Publish-Subscribeパターンというものも存在し、Publish-Subscribeパターンでは発行者が、この記事でいうサブジェクトの役割を果たすようです。>>

オブザーバ(Observer)・リスナー(Listener)

対象となる情報を観察(Observe)する主体。

購読者、サブスクライバ、リスナーとも呼ばれる。

サブジェクトの更新通知を受信する

観察情報の購読(サブスクライブ)は、Subjectが提供するregistObserver()によって行う。観察対象を購読することで、オブザーバになることができる。

反対に、removeObserver()によって、途中で購読を解除して、オブザーバを辞めることもできる。

必要なインターフェース

Subject.java
public interface Subject {
    public void registObserver(Observer observer);
    public void removeObserver(Observer observer);
    public void notifyObservers();
}
Observer.java
public interface Observer {
    public void doSomething(int data);
}

インターフェースの実装

SubjectSample.java
import java.util.ArrayList;
import java.util.List;

public class SubjectSample implements Subject {

    // サブジェクトはオブザーバを保持している
    private List<Observer> observers;

    // 観察対象の情報
    private int data = 0;

    public SubjectSample() {
        observers = new ArrayList<Observer>();
    }

    // 購読を開始する
    @Override
    public void registObserver(Observer o) {
        observers.add(o);
    }

    // 購読を解除する
    @Override
    public void removeObserver(Observer o) {
        observers.remove(o);
    }

    // 観察対象に変更があったことをオブザーバに対して通知する
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            // 引数に更新データを渡しても良いし、
            // getData()などを用意して、更新があったことだけを通知し、オブザーバ側から取得させても良い。
            observer.doSomething(data);
        }
    }

    // 観察対象のデータが変更される処理
    public void updateData(int newData) {
        data = newData;
        notifyObservers();
    }
}
ObserverSample.java
public class ObserverSample implements Observer{

    // サブジェクトへの参照を保持しておくと、あとで解除も行うことができる
    private SubjectSample subject;

    public ObserverSample(SubjectSample subject){
        this.subject = subject;
        // 購読を開始する
        subject.registObserver(this);
    }

    // 観察対象に更新があった場合、サブジェクト側で呼び出されるメソッド
    @Override
    public void doSomething(int data) {
        System.out.println("情報が更新されたため、何らかの処理を実行します。");
        System.out.println("最新のデータは" + data + "です。");
    }
}
Main.java
public class Main {
    public static void main(String[] args) {
        SubjectSample subject = new SubjectSample();
        ObserverSample observer = new ObserverSample(subject);

        // 観察対象の情報を変更する → サブジェクトが変更を通知 → オブザーバが通知を受信
        subject.updateData(100);
        // >>情報が更新されたため、何らかの処理を実行します。
        // >>最新のデータは100です。
    }
}

参考

Head Firstデザインパターン ―頭とからだで覚えるデザインパターンの基本

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2