Smalltlak の Observer パターン

MVC といえば Model と View-Contller 間のやりとりに Observerパターンを使います。Smalltalk の場合、Observerパターンのことを Dependency Mechanism と呼び、既にObject クラスに Subject としての機能は一通り実装済みになっています。(GoF本では、確か Observer の別名として Dependency があったハズ)

Subject 側

Object クラスの dependents access プロトコルには、"addObserver()" ならぬ addDependent: メソッドと、 おなじく "removeObserver()" ならぬ removeDependent: メソッドがあります。

一方 自身への変更メッセージ つまり、"notifyObservers()" の方は Object クラスの updating プロトコルにあります。"notifyObservers()" 相当のメソッドとしては、#changed / #changed: / #changed:with: と三つのインターフェイスがあります。

引数つきの #changed: / #changed:with: は、最初の引数には、Subject のどの側面(アスペクト)が変わったかを指定します。だいたいにおいて 変更のあったインスタンス変数名を が与えられます。

引数が二つある #changed:with: は、側面の名前(=変更のあったインスタンス変数名)だけでなく、その新しい値も伝えます。

Observer 側

#changed / #chenged: / #changed:with: メソッドの実装は実にシンプルで、こうです。

changed
    self changed: self

changed: aParameter 
    self dependents do:
        [:aDependent | aDependent update: aParameter]

changed: anAspect with: anObject
    self dependents do: 
        [:aDependent | aDependent update: anAspect with: anObject]

と言うわけで、変更を伝えられる aDependent(依存物、ようするに Observer) には、#update: または #update:with: メソッドが必要になります。

Subject が Object なら Observer も Object なので、こちらも Object クラスに実装があります。これも updating プロトコルに changed シリーズと一緒に実装されてます。「一人二役」なので
同じクラスの同じプロトコルにまとめられる訳です(けど、ちょっと混乱しそうかな)。

こちらの方は、

update: aParameter 
    ^ self

update: anAspect with: anObject
    ^ self update: anAspect

と、何もやらないメソッドになっているので オーバーライドしてあげる必要があります。


ディペンデンシィ機構は、「サクサクSmalltalk」で読んで知識としては知っていたのですが、実際に実装を確認するのは初めてです。プロトコル分けとか、やはりちょっとちがいますね〜。

特に #changed / #changed: / #changed:with: は、サクサクSmalltalk の解説だと「changed は changed: nil with: nil と同じ」とあるのに対して Squeak では changed は changed: self と同じになってる事は、ちょっと意外でした。