「Observer」という英単語は、「観察者」を意味します。
このパターンは、観察者となるオブジェクトが、観察対象となるオブジェクトからの状態変化の通知を受けそれに対する処理を行うパターンです。
「Observer」の観察対象となるオブジェクトのインタフェースを定義します。観察者を保持するメソッド、観察者への通知メソッド(状態が変化した際に「Observer」に通知)等を定義します。
※ 保持する観察者は複数でも可能
「Subject」の状態変化を監視します。(実際には、各「Subject」からの通知を処理する)
「Subject」からの通知(状態変化等の情報)受信用のメソッド(update)のインタフェースを定義します。
Observerパターンのクラス図
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 ■■