javascriptでObserverパターン


昨今のフロントエンド技術は進歩が圧倒的に早く、
jQueryわかります！MV*フレームワーク使ったことあります！
という程度ではもはや技術についていけなくなってしまっているこの頃です。

技術に追いついていけるだけの基礎体力をつけるべく、GUIプログラムにおけるMVCパターンのデザインパターンについて学習したことを書いていきます。

まずはObserverパターンから…
と思ってGUIにおけるMVCをいろいろ調べていたのですが、必須なのはObserverパターン（とその派生）だけだったという結論に至ったのでこれ以上javascriptのデザインパターンについては投稿するのやめました。

MVCについては、下記投稿や、
smalltalkのMVCについて目を通しておけば大丈夫だと考えます。

[MVC、本当にわかってますか？](http://qiita.com/tshinsay/items/5b1724baf32b8b5113c2)
[smalltalk mvc](http://www.cdl.im.dendai.ac.jp/~masuda/mvc.html)

# 投稿者のバックグラウンド

参考までに書いとく。

* WEBアプリケーションのサーバサイドプログラムメインに開発
* フロントエンドはMV*フレームワークなど利用できるが、概念までは説明出来ないゆるふわ系
* GUIプログラムはオブジェクト指向のない言語でなら経験あり

# Observerパターンとは？

イベントによって状態を更新するObserverと、そのObserverの登録や削除、イベントの通知を行うSubjectから構成される。

Subjectは登録されたObserverに対して通知を行うだけでよく、
Observerが何であるかということに関心を持たなくて良い。

と小難しく書いたが、要はSubjectとObserverに分けることでイベントの対象とイベントの発行が疎結合に出来るデザインパターン。

他に、Observerの状態に一貫性を持たせることが出来るという効用もあるようです。

# サンプルプログラムで見てみる

ボタンをクリックするとボックスのカラーが変わるというプログラムを想定。
ボタン１をクリックすると赤に、
ボタン２をクリックすると青に、
ボタン３をクリックすると赤に変わって青に変わる。

## Observerパターンを使わないプログラム

```coffeescript
btn1 = document.getElementById 'btn1'
btn2 = document.getElementById 'btn2'
btn3 = document.getElementById 'btn3'

box1 = document.getElementById 'box1' 
box2 = document.getElementById 'box2'

btn1.onclick = () ->
  to_red = 'red'

  box1.style.backgroundColor = to_red
  box2.style.backgroundColor = to_red

btn2.onclick = () ->
  to_blue = 'blue'

  box1.style.backgroundColor = to_blue
  box2.style.backgroundColor = to_blue

btn3.onclick = () ->
  to_red = 'red'
  to_blue = 'blue'

  box1.style.backgroundColor = to_red
  box2.style.backgroundColor = to_red

  setTimeout () ->
    box1.style.backgroundColor = to_blue
    box2.style.backgroundColor = to_blue
  , 500
```

各クリックイベントでは、イベントの対象となるオブジェクトを知っていなければ処理が書けないことが分かります。

## Observerパターンを適用する

### SubjectとObserverのオブジェクトを定義

```coffeescript
class Subject
  _observers = []

  add: (observer) ->
    _observers.push(observer)

  notify: (context) ->
    for observer in _observers
      observer.update(context)

class Observer
  update: (context) ->
```

* Subject

Observerの登録と、登録したObserverに対してイベントの通知を行う。
（本当はSubjectオブジェクトには登録したObserverを削除するメソッドも必要ですが、今回のサンプルでは利用しないので省略しています。）

* Observer

自身の状態を更新するメソッドを持ちます。

### 継承用関数の準備

上で定義したSubjectとObjectも抽象オブジェクトとして利用します。
そのため、継承用の関数を定義します。

```coffeescript
extend = (obj, extension) ->
  for key, prop of obj
    extension[key] = obj[key]
```

### 実際の処理

```coffeescript
btn1 = document.getElementById 'btn1'
btn2 = document.getElementById 'btn2'
btn3 = document.getElementById 'btn3'

for btn in [btn1, btn2, btn3]
  extend new Subject(), btn

box1 = document.getElementById 'box1' 
box2 = document.getElementById 'box2'

for box in [box1, box2]
  extend new Observer(), box

  box.update = (color) ->
    box.style.backgroundColor = color
  
  for btn in [btn1, btn2, btn3]
    btn.add box

btn1.onclick = () ->
  this.notify 'red'

btn2.onclick = () ->
  this.notify 'blue'

btn3.onclick = () ->
  self = this

  self.notify 'red'

  setTimeout () ->
    self.notify 'blue'
  , 500
```

各クリックイベントは、対象を知る必要がなくなり、
状態の通知のみを行えばよくなりました。

イベントの対象と発行が綺麗に分離できましたね :blush: 

# Observerパターンの派生

[出版-購読型モデル](http://ja.wikipedia.org/wiki/%E5%87%BA%E7%89%88-%E8%B3%BC%E8%AA%AD%E5%9E%8B%E3%83%A2%E3%83%87%E3%83%AB)
[イベント駆動型プログラミング](http://ja.wikipedia.org/wiki/%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E9%A7%86%E5%8B%95%E5%9E%8B%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0)