- 投稿日:2019-03-18T16:41:57+09:00
デザインパターン ~Observer~
1. はじめに
GoFのデザインパターンにおける、Observerパターンについてまとめます。
2. Observerパターンとは
- Observerという英単語は、観察者という意味になります。
- Observerパターンは、観察対象の状態が変化すると、観察者に対して通知が行われる方式です。
- Observerパターンは、状態変化に応じた処理を記述するときに有効です。
- GoFのデザインパターンでは、振る舞いに関するデザインパターンに分類されます。
3. サンプルクラス図
4. サンプルプログラム
ランダムに数を生成し、その変化に応じて「数字」及び「*」を表示するプログラムです。
4-1. Observerインターフェース
観察者を表すインターフェースです。
Observer.javapublic interface Observer { public abstract void update(NumberGenerator generator); }4-2. DigitObserverクラス
数字で数を表す行うクラスです。Observerインターフェースを実装します。
DigitObserver.javapublic class DigitObserver implements Observer { public void update(NumberGenerator generator) { System.out.println("DigitObserver:" + generator.getNumber()); } }4-3. GraphObserverクラス
簡易グラフで数を表す行うクラスです。Observerインターフェースを実装します。
GraphObserver.javapublic 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(""); } }4-4. NumberGeneratorクラス
数を生成するオブジェクトを表す抽象クラスです。
NumberGenerator.javaimport java.util.ArrayList; import java.util.Iterator; public abstract class NumberGenerator { private ArrayList<Observer> observers = new ArrayList<Observer>(); public void addObserver(Observer observer) { observers.add(observer); } public void deleteObserver(Observer observer) { observers.remove(observer); } public void notifyObservers() { Iterator it = observers.iterator(); while (it.hasNext()) { Observer o = (Observer) it.next(); o.update(this); } } public abstract int getNumber(); public abstract void execute(); }4-5. RandomNumberGeneratorクラス
ランダムに数を生成するクラスです。
RandomNumberGenerator.javaimport 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 < 10; i++) { number = random.nextInt(50); notifyObservers(); } } }4-6. Mainクラス
メイン処理を行うクラスです。
Main.javapublic 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(); } }4-7. 実行結果
DigitObserver:35 GraphObserver:*********************************** DigitObserver:33 GraphObserver:********************************* DigitObserver:40 GraphObserver:**************************************** DigitObserver:28 GraphObserver:**************************** DigitObserver:4 GraphObserver:**** DigitObserver:45 GraphObserver:********************************************* DigitObserver:7 GraphObserver:******* DigitObserver:30 GraphObserver:****************************** DigitObserver:31 GraphObserver:******************************* DigitObserver:22 GraphObserver:**********************5. メリット
Observerパターンでは、状態を持っているRandomNumberGeneratorクラスと、状態変化を通知してもらうDigitObserverクラス、GraphObserverクラスが登場します。そしてその2つの役目を繋いでいるものが、ObserverインターフェースとNumberGeneratorクラスになります。
RandomNumberGeneratorクラスは、自分が現在監視しているのが、DigitObserverインスタンスなのか、GraphObserverインスタンスなのかを知りません。しかし、observersフィールドに格納されているインスタンスが、Observerインターフェースを継承していることは知っており、updateメソッドを呼び出せることが保証されています。
一方、DigitObserverクラス、GraphObserverクラスは、自分を観察しているのがRandomNumberGeneratorインスタンスなのか、他のXXXNumberGeneratorインスタンスなのかを知りません。ただ、NumberGeneratorのサブクラスのインスタンスであり、getNumberメソッドを持っていることは知っています。
- 抽象クラスやインターフェースを使って、具象クラスから抽象メソッドを引きはがす
- 引数でインスタンスを渡すときや、フィールドでインスタンスを保持するときは、抽象クラスやインターフェースの型にしておく
このようにすることで、具象クラスの部分をカチッと交換することができます。6. GitHub
https://github.com/i-tanaka730/design_pattern
7. 参考