Observer パターン

「Observer」という英単語は、「観察者」を意味します。

このパターンは、観察者となるオブジェクトが、観察対象となるオブジェクトからの状態変化の通知を受けそれに対する処理を行うパターンです。


役割り

1. Subject(観察対象者)

「Observer」の観察対象となるオブジェクトのインタフェースを定義します。観察者を保持するメソッド、観察者への通知メソッド(状態が変化した際に「Observer」に通知)等を定義します。

※ 保持する観察者は複数でも可能

2. ConcreteSubjectA・B(具体的な観察対象者)
「Subject」で定義したインタフェースを実装します。「Observer」への通知は、自身に保持している「Observer」オブジェクトの通知受信用メソッドを呼出すことにより実現します。
3. Observer(観察者)

「Subject」の状態変化を監視します。(実際には、各「Subject」からの通知を処理する)

「Subject」からの通知(状態変化等の情報)受信用のメソッド(update)のインタフェースを定義します。

4. ConcreteObserver(具体的な観察者)
「Observer」で定義したインタフェースを実装します。「Subject」から状態受信用のメソッドの呼出しが行われると、その呼出元の状態を元に処理を行います。
5. Client(利用者)
「Observer」パターンを適用したクラスを用い処理を行います。

▲PageTop

クラス図

Observerパターンのクラス図

Observerパターン クラス図

▲PageTop

サンプル

ソースコード

1. Subject.java

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

public abstract class Subject {
    private List<Observer> observers = new ArrayList<Observer>(); // 複数のオブザーバの保持が可能
    private Random random = new Random();
    public void addObserver(Observer observer) {
        observers.add(observer);
    }
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }
    public void notifyObservers() {
        Iterator<Observer> it = observers.iterator();
        while (it.hasNext()) {
            it.next().update(this);
        }
    }
    public int getRandomNumber() {
        return random.nextInt(100);
    }
    public abstract int getStatus();
    public abstract String getName();
    public abstract void run();
}

2-1. ConcreteSubjectA.java

public class ConcreteSubjectA extends Subject {
    private String subjectName = "ConcreteSubjectA";
    private int status = 0;
    public int getStatus() {
        return status;
    }
    public String getName() {
        return subjectName;
    }
    public void run() {
        int randomNumber = 0;
        randomNumber = getRandomNumber();
        if (status < randomNumber) {
            System.out.println(subjectName + "の状態が " + status + " -> " + randomNumber + " に変わります。");
            status = randomNumber;
            notifyObservers();
        }
    }
}

2-2. ConcreteSubjectB.java

public class ConcreteSubjectB extends Subject {
    private String subjectName = "ConcreteSubjectB";
    private int status = 100;
    public int getStatus() {
        return status;
    }
    public String getName() {
        return subjectName;
    }
    public void run() {
        int randomNumber = 0;
        randomNumber = getRandomNumber();
        if (status > randomNumber) {
            System.out.println(subjectName + "の状態が " + status + " -> " + randomNumber + " に変わります。");
            status = randomNumber;
            notifyObservers();
        }
    }
}

3. Observer.java

public abstract class Observer {
    public abstract void update(Subject subject);
}

4. ConcreteObserver.java

public class ConcreteObserver extends Observer {
    private String observerName = "ConcreteObserverA";
    public void update(Subject subject) {
        System.out.println("観察者:" + observerName + System.getProperty("line.separator") + "通知者:"
            + subject.getName() + System.getProperty("line.separator") + "状態 :" + subject.getStatus());
    }
}

5. Client.java

public class Client {
    public static void main(String[] args) {
        Observer ob = new ConcreteObserver();
        Subject sb1 = new ConcreteSubjectA();
        Subject sb2 = new ConcreteSubjectB();
        sb1.addObserver(ob);
        sb2.addObserver(ob);
        for (int i = 0; i < 50; i++){
            sb1.run();
            sb2.run();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("■■ END ■■");
    }
}

実行結果

C:\sample\desin_pattern\observer>javac Client.java [Enter]

C:\sample\desin_pattern\observer>java Client [Enter]
ConcreteSubjectAの状態が 0 -> 16 に変わります。
観察者:ConcreteObserverA
通知者:ConcreteSubjectA
状態 :16
ConcreteSubjectBの状態が 100 -> 86 に変わります。
観察者:ConcreteObserverA
通知者:ConcreteSubjectB
状態 :86
ConcreteSubjectAの状態が 16 -> 85 に変わります。
観察者:ConcreteObserverA
通知者:ConcreteSubjectA
状態 :85
ConcreteSubjectBの状態が 86 -> 44 に変わります。
観察者:ConcreteObserverA
通知者:ConcreteSubjectB
状態 :44
ConcreteSubjectAの状態が 85 -> 96 に変わります。
観察者:ConcreteObserverA
通知者:ConcreteSubjectA
状態 :96
ConcreteSubjectBの状態が 44 -> 15 に変わります。
観察者:ConcreteObserverA
通知者:ConcreteSubjectB
状態 :15
ConcreteSubjectBの状態が 15 -> 10 に変わります。
観察者:ConcreteObserverA
通知者:ConcreteSubjectB
状態 :10
ConcreteSubjectBの状態が 10 -> 0 に変わります。
観察者:ConcreteObserverA
通知者:ConcreteSubjectB
状態 :0
ConcreteSubjectAの状態が 96 -> 98 に変わります。
観察者:ConcreteObserverA
通知者:ConcreteSubjectA
状態 :98
■■ END ■■
        

▲PageTop