【Java】Observer パターン【デザインパターン】
目次
Observerパターンについて
Observerパターンとは
- Observerパターンは、観察対象の状態が変化すると、観察者に対して通知が行われる方式です。
- 状態変化に応じた処理を記述するときに有効です
サンプルプログラム
- Observerパターンを使って、数を沢山生成するオブジェクトを観察者が観察して、その値を表示する例を取り上げます
- 表示の方法は、観察者によって変わります
- 各クラスの役割は以下のようになっています
名前 | 役割 |
---|---|
Observer | 観察者を表すインターフェース |
NumberGenerator(Subject) | 数を生成するオブジェクトを表す抽象クラス |
RandomNumberGenerator(ConcreteSubject) | ランダムに数を生成するクラス |
DigitObserver(ConcreteObserver) | 数字で数を表す行うクラスで、Observerインターフェースを実装する |
GraphObserver(ConcreteObserver) | 簡易グラフで数を表す行うクラスで、Observerインターフェースを実装 |
Observerインターフェース
- updateメソッドを呼びだすのは、数を生成するNumberGeneratorです
- 自分の内容が変更されたことをObserberに伝えます
public interface Observer { public abstract void update(NumberGenerator generator); }
NumberGeneratorクラス
- 数を生成する抽象クラスです
- 実際の数の生成と、取得はサブクラスが実装します
import java.util.ArrayList; import java.util.Iterator; public abstract class NumberGenerator { private ArrayList observers = new ArrayList(); // Observerたちを保持 public void addObserver(Observer observer) { // Observerを追加 observers.add(observer); } public void deleteObserver(Observer observer) { // Observerを削除 observers.remove(observer); } public void notifyObservers() { // Observerへ通知 Iterator it = observers.iterator(); while (it.hasNext()) { Observer o = (Observer)it.next(); o.update(this); } } public abstract int getNumber(); // 数を取得する public abstract void execute(); // 数を生成する }
RandomNumberGeneratorクラス
- 乱数を生成します
import java.util.Random; public class RandomNumberGenerator extends NumberGenerator { private Random random = new Random(); // 乱数生成機 private int number; // 現在の数 public int getNumber() { // 数を取得する return number; } public void execute() { for (int i = 0; i < 20; i++) { number = random.nextInt(50); notifyObservers(); } } }
DigitObserverクラス
* 観察した値を数字で表示するためのものです
public class DigitObserver implements Observer { public void update(NumberGenerator generator) { System.out.println("DigitObserver:" + generator.getNumber()); try { Thread.sleep(100); } catch (InterruptedException e) { } } }
GraphObserverクラス
- 観察した値を*****のように簡易グラフで表示します
public class GraphObserver implements Observer { public void update(NumberGenerator generator) { System.out.print("GraphObserver:"); int count = generator.getNumber(); for (int i = 0; i < count; i++) { System.out.print("*"); } System.out.println(""); try { Thread.sleep(100); } catch (InterruptedException e) { } } }
Mainクラスで動作確認
- NumberGeneratorのインスタンスを一個、その観察者を二個作ります
public class Main { public static void main(String[] args) { NumberGenerator generator = new RandomNumberGenerator(); Observer observer1 = new DigitObserver(); Observer observer2 = new GraphObserver(); generator.addObserver(observer1); //観察者登録 generator.addObserver(observer2); generator.execute(); //数を生成 } }
Observerパターンのメリット
- 状態を持っているRandomNumberGeneratorクラスと、状態変化を通知してもらうDigitObserverクラス、GraphObserverクラスが登場します
- その2つの役目を、ObserverインターフェースとNumberGeneratorクラスが繋ぎます
- RandomNumberGeneratorクラスは、自分が現在監視しているの(通知する相手)が、DigitObserver/GraphObserverインスタンスなのかを知りません。
- しかし、observersフィールドに格納されているインスタンスが、Observerインターフェースを継承していることは知っており、updateメソッドを呼び出せることが保証されています。
- 一方、DigitObserverクラス、GraphObserverクラスは、自分を観察しているのがRandomNumberGeneratorインスタンスなのか、他のXXXNumberGeneratorインスタンスなのかを知らず、NumberGeneratorのサブクラスのインスタンスであり、getNumberメソッドを持っていることは知っています。
- 具象クラスの交換可能性を高くするポイントは以下の2点です
- MVCモデルの中の、ModelとViewの関係は、 ObserverパターンのSubjectとObserverの関係に相当します
- Modelは、"表示形式に依存しない内部モデルを操作する"役割で、Viewは "Modelをどのように見せるか" 管理します。一般的に、1つのModelに対して、複数のViewが対応します。
今日のポイント
- Observerパターンは、観察対象の状態が変化すると、観察者に対して通知が行われる方式です
- 状態を持っているクラス(ConcreteSubject)と、状態変化を通知してもらうクラスConcreteObserver)が登場します
- お互いに通知する相手は知らないので、独立性を高めることができます。
- 具象クラスの交換可能性を高くするには、以下が重要です
- MVCモデルの中の、ModelとViewの関係は、 ObserverパターンのSubjectとObserverの関係に相当します
本日もお疲れ様です😊