デザインパターン（Design Pattern）#Observer

設計を意識したコードが書けるようになる為に、デザインパターン修行しました。
他のDesign Patternもちょくちょく出していきます。

## 前置き
* [増補改訂版Java言語で学ぶデザインパターン入門](http://www.hyuki.com/dp/)をJavaからPythonにしてます。（Pythonは3.4.2）
* [githubにコード置いてあります（まだ動かないものもある）](https://github.com/Nirperm/Design-Pattern)

デザインパターンをどういう時に、何を、どう使うのかを理解することが一先ずの目標。
（Javaというか静的型付言語は初めてで、且つpython歴もそんなに長くないので、Pythonistaぽっくないところがあると思います。ご指摘ございましたらご教授ください。）

今回は、振る舞いに関するパターンObserver。

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

## 概要
ここで作るサンプルプログラムは、数をたくさん生成するオブジェクトを観察者が観察して、その値を表示するというものです。ただし、表示の方法は観察者によって異なります。DigitObserverは値を数字で表示しますが、GraphObserverは値を簡易グラフで表示します。

## 全体のクラス図
![](https://cacoo.com/diagrams/m3gOtiAK8WNr2rPR-3F872.png?t=1432781906515)

```observer.py
from abc import ABCMeta, abstractmethod


class Observer(Exception):
    __meta__ = ABCMeta

    @abstractmethod
    def update(self, generator):
        pass
```
observerインタフェースは、「観察者」を表現するインタフェースです。具体的な観察者は、このインタフェースで実装します。

updateメソッドを呼び出すのは、数を生成するNumberGeneratorです。
updateメソッドはNumberGeneratorが「私の内容が更新されました。表示の方も更新してください」とobserverに伝えるためのメソッドです。
<br>

```number_generator.py
from abc import ABCMeta, abstractmethod


class NumberGenerator(metaclass=ABCMeta):

    __observers = []

    def add_observer(self, observer):
        self.__observers.append(observer)

    def delete_observer(self, observer):
        self.__observers.remove(observer)

    def notify_observers(self):
        for observer in self.__observers:
            observer.update(self)

    @abstractmethod
    def get_number():
        pass

    @abstractmethod
    def execute():
        pass
```
NumberGeneratorクラスは数を生成する抽象クラスです。実際の数の生成（executeメソッド）と、数を取得する部分（get_numberメソッド）はサブクラスが実装することを期待して、抽象メソッドになっています。

observersフィールドは、NumberGeneratorを観察しているobserverたちを保存しているフィールドです。

add_observerはobserverを追加するメソッド、delete_observerはobserverを削除するメソッドです。

notify_observersメソッドは、observer全員に対して「私の内容が更新されたので、あなたの表示を更新してください」と伝えるものです。このメソッドの中では、observersの中のobserverたち1人1人のupdateメソッドを呼び出しています。
<br>

```random_number_generator.py
import random
from number_generator import NumberGenerator


class RandomNumberGenerator(NumberGenerator):

    __number = 0

    def __init__(self):
        self.__rand = random

    def get_number(self):
        return self.__number

    def execute(self):
        for i in range(0, 20):
            self.__number = self.__rand.randint(0, 50)
            self.notify_observers()
```
RandomNumberGeneratorクラスは、NumberGeneratorのサブクラスで乱数を発生するものです。

randomフィールドには、乱数発生器が保持され、numberフィールドには現在の乱数値が保持されます。

get_numberメソッドは、numberフィールドの値を返します。

executeメソッドは乱数(0~49の整数)を20個生成し、そのつどnotify_observersを使って、観察者に通知をします。
<br>

```digit_observer.py
import time
import logging
from observer import Observer


class DigitObserver(Observer):

    def update(self, generator):
        print('DigitObserver:' + str(generator.get_number()))
        try:
            time.sleep(1)
        except InterruptedError as e:
            logging.exception(e)
```
DigitObserverクラスは、observerインタフェースを実装しているクラスで、観察した数を「数字」で表示するためのものです。updateメソッドの中で引数として与えられたNumberGeneratorのget_numberメソッドを使って数を取得し、表示します。表示の様子がわかるように間隔をあけています。
<br>

```graph_observer.py
import sys
import time
from observer import Observer


class GraphObserver(Observer):

    def update(self, generator):
        sys.stdout.write('GraphObserver:')
        count = generator.get_number()
        for i in range(0, count):
            sys.stdout.write('*')
        print('')
        try:
            time.sleep(1)
        except InterruptedError:
            pass
```
GraphObserverクラスも、Observerインタフェースを実装しているクラスです。このクラスは観察した数を*****のような「簡易グラフ」で表します。
<br>

```main.py
from digit_observer import DigitObserver
from graph_observer import GraphObserver
from random_number_generator import RandomNumberGenerator


def main():
    generator = RandomNumberGenerator()
    observer1 = DigitObserver()
    observer2 = GraphObserver()
    generator.add_observer(observer1)
    generator.add_observer(observer2)
    generator.execute()


if __name__ == "__main__":
    main()
```
RandomNumberGeneratorのインスタンスを1個作り、その観察者を2個作ります。observer1はDigitObserverの、observer2はGraphObserverのインスタンスです。

add_observerメソッドを使って観察者を登録した後、generator.executeを使って数を生成します。

実行結果

```
DigitObserver:17
GraphObserver:*****************
DigitObserver:43
GraphObserver:*******************************************
DigitObserver:47
GraphObserver:***********************************************
DigitObserver:34
GraphObserver:**********************************
DigitObserver:30
GraphObserver:******************************
DigitObserver:50
GraphObserver:**************************************************
DigitObserver:7
GraphObserver:*******
DigitObserver:40
GraphObserver:****************************************
DigitObserver:39
GraphObserver:***************************************
DigitObserver:41
GraphObserver:*****************************************
DigitObserver:38
GraphObserver:**************************************
DigitObserver:3
GraphObserver:***
DigitObserver:22
GraphObserver:**********************
DigitObserver:26
GraphObserver:**************************
DigitObserver:0
GraphObserver:
DigitObserver:23
GraphObserver:***********************
```

## まとめ
一方のオブジェクトがもう一方のオブジェクト(観察者) を登録するメソッドを追加することによって、監視対象となりました。監視対象オブジェクトはその変更時に登録オブザーバーにメッセージを送信します。

オブザーバーがその情報をどう処理するかは、監視対象オブジェクトにとっては関係なく、どんなクラスのオブジェクトでも構いません。

オブジェクトは必ずしも理由を理解することなく、その結果、オブジェクト間の依存度を下げることができ、通知先の管理を観察者が行うことで、観察対象は通知側を意識する必要が無くなりました。

## 参考
* [サルでもわかる 逆引きデザインパターン](http://www.nulab.co.jp/designPatterns/designPatterns1/designPatterns1-2.html)
* [TECHSCOREデザインパターン](http://www.techscore.com/tech/DesignPattern/foundation/foundation1.html/)
* [Wikipedia Software design pattern]([http://en.wikipedia.org/wiki/Software_design_pattern)
* [Wikipedia デザインパターン](http://goo.gl/lRi5)
* [Ruby 2.0.0で学ぶ、14個のデザインパターンを作りました[GoF][Design Pattern]](http://morizyun.github.io/blog/ruby-design-pattern-matome-mokuzi/)
* [Rubyによるデザインパターン5原則](http://qiita.com/kidach1/items/4b63de9ad5a97726c50c)