2010年9月5日日曜日

Observerパターン

Observerとは、観察者のことです。Observerパターンとは、作業者の状態を監視する役のクラスがあるパターンです。


先に、監視されるクラス(作業をするクラス)を説明すると、コードとしては以下の通りです。

  1. public abstract class Subject {  
  2.     private List<Observer> observerList = new ArrayList<Obsever>();  
  3.   
  4.     public void addObserver(Observer observer) {  
  5.         observerList.add(observer);  
  6.     }  
  7.   
  8.     protected void notifyObservers() {  
  9.     // 参考本ではこのメソッドはpublicになっていたが、子クラスからしか呼ばれないので、protectedにした。  
  10.         Iterator itr = observerList.iterator();  
  11.         while (itr.hasNext()) {  
  12.             Observer observer = (Observer) itr.next();  
  13.             observer.update(this);  
  14.         }  
  15.     }  
  16.   
  17.     public abstract void execute();  
  18.   
  19.     // その他、observerから呼んで欲しいメソッドを定義  
  20. }  

まず、監視する人をこの人は知っています。複数人いてもよいようにListになっています。作業をするメソッドはexecute()で実装しますが、何か状態が変わったときはexecute()内でnotifyObservers()を呼び、監視者に通知します(Observer#update()を呼びます)

監視するクラスについて説明します。監視者は誰も作業者の状態変更通知を受け取れるようにupdate()を実装します。そーいうことで、Observerインターフェースを用意しておきます。

  1. public interface Observer {  
  2.     void update(Subject subject);  
  3. }  

Observerインターフェースの実装クラスは例えばこんな感じです。

  1. public class SampleObserver implements Observer {  
  2.     public void update(Subject subject) {  
  3.         // Subjectクラスのメソッドを呼び、例えばコンソールに出力する、ログに残すなどの処理を行う。  
  4.     }  
  5. }  

この後は、Subjectクラスの子クラスを作り、mainクラスからその子クラスのインスタンスを作って、SampleObserverをaddし、execute()を呼べばいいでしょう。

監視をするパターン自体は難しくないと思います。ポイントとしては、どのクラスでも作業者、監視者になれるよう、親クラス(厳密に言うと、作業者はabstractクラスで、監視者はinterface)を定義してあげて、具体的な作業者、監視者はそれらを継承・実装することで、汎用性があがるということです。

ただし、注意しなければならないのは、SubjectからObserverへ通知をした後に、ObserverからSubjectへ何かしらの指示を行った場合です。このとき、Observerからの指示でSubjectの状態が変化すると、またそのタイミングでObserverへ通知を行ってしまうからです。フラグでも用意して、防ぐようにしましょう。

ちなみに、Observer#update()をSubjectが呼ぶ際は、Subject自身を引数に入れています。が、例えば値の更新を通知するだけならば、引数に値を入れて渡すでも良いと思います。ただし、この場合において、もし、Observerが複数のSubjectを監視しているならば、どのSubjectからの変更通知なのか分からないです。Observerにどの程度の情報を渡すかは実装する際に検討すべきでしょう。


しかし、このパターンは監視というより、通知ですよね・・・


関連パターン
Mediatorパターン」Mediatorは、個々の作業者との調整役という位置づけであり、Observerでは、SubjectがObserverに通知をして同期を取ることに主眼を置いています。

Mediatorパターン

Mediatorとは仲介役とか相談役とかという意味です。個々人がバラバラに作業しているところをまとめてくれます。個々人同士であーだこーだ言い合ってもまとまらない場合には全体を俯瞰できて、適切に指示できる人が欲しいですよね。

Mediatorパターンは個々の担当者の状態を把握し、次になるべき状態を個々の担当者に指示する役目がいるパターンです。ここで言っている状態とは、例えば、あるログインフォームで言うと

ゲストユーザか正規ユーザか
ユーザ名が入力できる入力できない
パスワードが入力できる入力できない
OKボタンが押せる押せない
・・・

などなどです。Mediatorは例えば、「正規ユーザが選択されている状態」かつ「ユーザ名とパスワードを入力されている状態」というのを担当者から聞いたら、「OKボタンを押せるようにする」という風にOKボタン担当者に指示します。


サンプルソースは・・・考えておきます(´・ω・`)


関連パターン
Facadeパターン」Mediatorは双方向だが、Facadeは一方向のみ。
「Observerパターン」(勉強中)