トップページ - srMVUnit.pas
Java の Observable と Observer を Delphiに移植した TObservable と TObserver クラスです。
mv100.zip (サンプルプログラムが含まれています)
説明は Sun の JavaTM 2 Platform, Standard Edition, 1.4.0 API 仕様 から拝借しています。
TObservable クラスのメソッド一覧です。Java のオリジナル:Observable
メソッド | スコープ | 説明 |
AddObserver(AObserver: TObserver) | public | オブジェクトのオブザーバセットにオブザーバを追加します。 |
DeleteObserver(AObserver: TObserver) | public | オブジェクトのオブザーバセットからオブザーバを削除します。 |
NotifyObservers | public | オブジェクトが、HasChanged メソッドに示されるように変更されていた場合、そのすべてのオブザーバにそのことを通知し、次に ClearChanged メソッドを呼び出して、このオブジェクトがもはや変更された状態でないことを示します。 |
NotifyObservers(AArg: TObject) | public | オブジェクトが、HasChanged メソッドに示されるように変更されていた場合、そのすべてのオブザーバにそのことを通知し、次に ClearChanged メソッドを呼び出して、このオブジェクトがもはや変更された状態でないことを示します。 |
DeleteObservers | public | オブザーバリストを消去します。 |
SetChanged | protected | Observable オブジェクトを変更されたものとしてマーキングします。 |
ClearChanged | protected | オブジェクトがもはや変更された状態ではないこと、すなわち、最新の変更がすべてオブザーバに通知されたことを示します。 |
HasChanged | public | オブジェクトが変更されたかどうかを判定します。 |
CountObservers | public | Observable オブジェクトのオブザーバの数を返します。 |
TObserver のメソッド一覧です。Java のオリジナル:Observer
メソッド | スコープ | 説明 |
Update(AObservable:TObservable; AArg:TObject) | public | 被監視オブジェクトに変更があると、このメソッドが呼び出されます。 |
Java の Observable は interface として定義されています。
Delphi にも interface はあるわけですが、これは COM 向けの言語仕様であり、最低でも IUnknown を継承しないといけません。従って、Delphi で TObserver を interface として定義してしまうと、これを実装するクラスでは必要も無いのに IUnknown で宣言されているメソッド(QueryInterface,_AddRef,_Releaseの3つ)を実装しなければならなくなります。以前はこの方法(空のメソッドを定義する)で interface を使っていたこともあったのですが、あまりに見た目が悪いので止めました。
そのための副作用もあります。TObserver はビューですから、通常は TForm 等のビジュアルコンポーネントが対象になります。しかしDelphi は多重継承を許していませんので、このままでは TObserver を組み込むことが出来ません。そこで、フォームがビュークラスを「所有」し、ビュークラスがフォームに対して更新通知を伝える事で解決します。
まず、Form に更新用のメソッドを定義します。
TMyForm = class(TForm) private FMyFormListener: TObserverListener; procedure UpdateView(AObservable: TObservable); … end;
TMyForm と同じ unit に、TObservable からの更新を TMyForm に伝えるクラスを定義します。
TObserverListener = class(TObserver) public procedure Update(AObservable:TObservable; AArg:TObject);override; end;
TObserverListenerの実装は単純です。
procedure TObserverListener.Update(AObservable: TObservable); begin MyForm.UpdateView(AObservable as TModel); end;
私はこういう形で使用しています。
また、AddObserver するタイミングも問題です。単純なアプリケーションの場合、私はプロジェクトソース内で AddObserver しています。もっと複雑な場合、例えば Observer と Observable の生存期間が一致しないようなアプリケーションの場合には、TMyForm が自分自身で AddObserver するか、Observer と Observable の接続関係を管理するためのクラスを別途作ります。
Listenerクラスがする事はフォームの更新メソッドを呼ぶだけなわけで、そういう意味ではListenerクラスのインスタンスはひとつだけにして、そのクラスにフォームそのものか更新メソッドのポインタを登録するような形でも良いかもしれません。
ビューは自分がモデルから関連付けを削除されたタイミングを知る事が出来ません。関連付けされていない時に空画面を表示したいような場合にはこのタイミングを知りたくなります。これは TObserver のイベントとして実装する事が出来ます。
とにかく豪華にしようと思えば色々と出来ますが、こういうプリミティブなクラスは単純な方が使い易いので、するとすれば別ものとして作ることになると思います。
トップページ - srMVUnit.pas