LoginSignup
0
1

More than 1 year has passed since last update.

「Observer」デザインパターンがなんとなく分かるようになる話

Posted at

はじめに

こちらの記事はGoFのデザインパターンに基づいたObserverパターンについての解説になります。
Observerパターンを調べたけどイマイチよく分からんという方のために
具体的な実装例からイメージを掴めてもらえるような記事にしました。
※Observerの一般的な説明はこちら

<参考>
Java言語で学ぶデザインパターン入門

Observerパターンとは

Observerとは、「観察者」という意味です。
すなわち、観察対象の状態が変化すると、観察者に対して通知がされます。
Observerパターンは、状態変化に応じた処理を記述するときに有効です。

サンプルプログラムの構成

クラス名   説明
Observer 観察者を表すインターフェース
NumberGenerator 数を生成するオブジェクトを表す抽象クラス
RandomNumberGenerator ランダムに数を生成するクラス
DigitObserver 数字で数を表示するクラス
GraphObserver 簡易グラフで数を表示するクラス
Main 動作テスト用のクラス

Observerインターフェース

「観察者」を表現するインターフェース

public interface Observer {
    public abstract void update(NumberGenerator generator);
}

・updateメソッドはNumberGeneretorクラスで呼び出される

NumberGeneratorクラス

数を生成するオブジェクトを表す抽象クラス

import java.util.ArrayList;
import java.util.Iterator;

public abstract class NumberGenerator {
    private ArrayList observers = new ArrayList();

    // Observerを追加する
    public void addObserver(Observer observer) {
        observers.add(observer);
    }
    // Observerを削除する
    public void deleteObserver(Observer observer) {
        observers.remove(observer);
    }
    // Observer全員に対して「私の内容が更新されたので、あなたの表示を更新して下さい」と伝える
    public void notifyObserver() {
        Iterator it = observers.iterator();
        while(it.hasNext()) {
            Observer o = (Observer)it.next();
            o.update(this);
        }
    }

    // 数を取得する
    public abstract int getNumber();
    // 数を生成する
    public abstract void execute();
}

・Observerへ通知するnotifyObserver()の中でupdateメソッドを呼ぶことで、
 Observer全員に対して表示を更新するように伝えている

RandomNumberGeneratorクラス

NumberGeneratorのサブクラスで乱数を生成するクラス

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);
            notifyObserver();
        }
    }
}

・executeメソッドは乱数を20個生成し、
 生成する毎にnotifyObserver()を使って、観察者に通知する。

DigitObserverクラス

観察した数を数字で表示するクラス
Observerインターフェースを実装

public class DigitObserver implements Observer{
    public void update(NumberGenerator generator) {
        System.out.println("DigitObserver:" + generator.getNumber());
        // sleepは表示を見やすくするためにつけている
        try {
            Thread.sleep(1000);
        } catch(InterruptedException e) {
        }
    }
}

・updateメソッドを実装

GraphObserverクラス

観察した数を*****のような表現で表示をするクラス
Observerインターフェースを実装

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("");
        // sleepは表示を見やすくするためにつけている
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
        }
    }
}

・updateメソッドを実装

Mainクラス

動作テスト用のクラス

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();
    }
}

実行結果

DigitObserver:7
GraphObserver:*******
DigitObserver:1
GraphObserver:*
DigitObserver:9
GraphObserver:*********
DigitObserver:3
GraphObserver:***
DigitObserver:12
GraphObserver:************
(以下略)

プログラムの解説

状態を持っているRandomNumberGeneratorクラスがあって、
乱数が生成されると、状態が変わったということでnotifyObserver()を呼び出します。
norifyObserver()が呼び出され、各Observerそれぞれが持つ実装されたupdateメソッドが実行されます。

「観察」ではなく「通知」

Observerは観察者という意味なので、変更を「観察」していると考えられますが、
実際の動きを見ると能動的に観察しているわけではなく、
状態が変わったと「通知」されるのを受動的に待っているような作りとなっています。

開発をしているとよく遭遇するデザインパターンなので、
具体的な実装例からなんとなくでもイメージを掴めてもらえると嬉しいです。

0
1
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
0
1