Entry

Visitor パターンが使われる局面とか

2010年09月09日

国内のリソースだけかもしれないんですけれど,ネットにある Visitor パターンの説明が Iterator パターンとごっちゃになっているものがかなりあるのに気づきました。「階層構造をトラバースするのが Visitor パターン」とかいったトンデモな説明もあって,うわぁ……。元ネタはどこからきているんだろう。また,具体例についても実用的な例は少ないみたい。

Visitor パターンは,データとその扱いを分離するために使われるパターンです。あたしの周りでは割とあちこちで使われていて,よく目にしています。しかし,このパターンは,製品と呼べるようなプログラムを書く向きじゃないと,具体的に必要となるな局面を想像できないかもしれません。反対に,Visitor パターンの説明がしょぼいと,その人が実務でソフトウェアを作っていないことも分かってしまうんじゃないか,とも。

パターンの詳細は GoF 本に譲るとして,Visitor パターンがよく使われるのは,データ構造をさまざまな方法で操作したい場合だったりします。

オブジェクト指向における再利用のためのデザインパターン
エリック ガンマ ラルフ ジョンソン リチャード ヘルム ジョン ブリシディース
ソフトバンククリエイティブ
売り上げランキング: 13145
おすすめ度の平均: 4.5
3 内容は良いが翻訳が。。。
4 デザインパターン教へようこそ
5 設計の再利用
5 設計をする人は一度見る価値あります
5 オブジェクト指向言語を用いた開発者に必携の本

「データ構造をさまざまな方法で操作したい場合」とは,具体的にどゆ場合か。例えば,文書を扱うソフトを作っているとしますよね。ワープロとかプレゼン用のアプリケーションを思い浮かべてもらえばいいと思います。このソフト,普段は自前のフォーマットでファイルに読み書きしているんですけれど,便利機能として MS Word や MS Excel,それに HTML や PDF なんかにも出力できちゃったりします。便利ですね。

で,こゆソフトを作るとき,自前のデータ構造は当然持っているわけです。例えば,ページクラスとか,テキストボックスクラスとか。テーブルクラスとその子要素のセルクラスなんかもあるかもしれません。自前のフォーマットで出力するときは,こいつを単純にシリアライズすればいい。

しかし,MS Word や MS Excel に出力するときは,出力方法が異なることから,「同じデータ構造に対して異なる処理」を行う必要があります。ここがミソです。

これを何も考えずに作るなら,データ構造は Composite パターンなんかを使ってごにょごにょやるとして,出力用の関数は出力するフォーマット毎に作る必要があります。Word 形式でテキストオブジェクトを出力するなら,Text クラスに Text::outWord() 的な関数を作るわけですね。こいつをサポートするフォーマットの数だけ,Text クラスに用意する必要があります。Text::outPDF() とか Text::outExcel() とかいった具合です。

しかし,これは非常に非効率です。まず,サポートするフォーマットが増えた場合のことを考えると,ひとつフォーマットが増えるたびにすべてのクラスにサポートする関数を追加する必要があります。また,すべてのクラスに修正がかかるということは,すべてのクラスをコンパイルしなおさなくてはいけない,ということでもあります。おもちゃプログラムならコンパイルも一瞬ですけど,大規模なプログラムではすごく時間がかかるんですね。こゆのも避けたい。

そこで,それぞれの出力機能を「データの内容を出力する」という機能に抽象化(汎化)することを考えることになります。Outputter とかいったクラス(インターフェイス)を作るわけです。Excel 形式で出力したければ,こいつを継承して ExcelOutputter というクラスを作って,Excel 形式で出力するのに必要な機能をすべて盛り込みます。Visitor パターンの Accepter であるデータ構造側は,基底クラスである Outputter 型で受けるので,どの形式で出力されるのかは知る必要がなくなります。

Visitor パターンというのは,こゆものです。もちろんこのパターン,出力形式がひとつしかないプログラムでも有用で,例えば,データ構造の全ダンプを取るためにデバッグライト用の Visitor クラスを追加することなんかが簡単にできます。出力先が特殊なデバイスで,本番環境にしかそのデバイスがない場合なんかも,ダミーの出力クラスを Visitor として使うことでシステムテストの直前までテストすることもできる。

また,Visitor はクラスだから,その状態を Visitor オブジェクト内で独自に管理することができます。例えば,PDF のファイルフォーマットなんかは,各オブジェクト(PDF におけるオブジェクト)のファイル上の位置(バイトオフセット)を相互参照表(xref)というテーブルで管理しています。つまり,あるデータ構造を出力する場合,ファイルのどこにオブジェクトを書き込んだか,管理している必要があるんですね。これを管理する場合も,PDFOutputter クラスが内部で書き込み位置を管理していれば,相互参照表を簡単に構成することができます。

使う局面さえ知っていればかなり強力なパターンになるんだけれども,なんつか,あまりなじみはないみたい。ま,たしかに,理解しづらいパターンだとは思うんですけどね。

Trackback
Trackback URL:
Ads
About
Search This Site
Ads
Categories
Recent Entries
Log Archive
Syndicate This Site
Info.
クリエイティブ・コモンズ・ライセンス
Movable Type 3.36
Valid XHTML 1.1!
Valid CSS!
ブログタイムズ

© 2003-2012 AIAN