Object? HASH reference? - メソッドと tied ハッシュ 両方のインターフェイスを持つオブジェクト
今回は一般的なオブジェクトとしても、またハッシュリファレンスとしても使用できるオブジェクトのインターフェイスと その実装方法について考えてみよう。つまり:
$obj->foo();
$obj->{foo};
両方のインターフェイスを正式にサポートするオブジェクトだ。
Perlでは一般的にオブジェクトをハッシュリファレンスとして扱うことは良くないこととされている。 それは、普通オブジェクトはblessされたハッシュリファレンスとして実装され、そのハッシュに直接アクセスする ことはカプセル化を壊すことになるからだ。
しかし、ハッシュとしてアクセスした方が自然なオブジェクトもある。そんな時に使われるのがtied hash、最近は あまり使われていないようだが、*DBM_File 系のモジュールでおなじみのアレ。
また、別の話としてPerlではオブジェクトに存在しないメソッドが呼ばれたときに呼び出されるAUTOLOADという 仕組みが用意されている。その使い方については 弾さんの説明 を読んでいただくとして、この仕組みを 利用してメソッドを仮想的または動的に作ることができる。
という前振りをしつつ、、、
XML名前空間を抽象化する Namespace というクラスを考える。
Namespaceは
$xhtml_ns = Namespace->new('http://www.w3.org/1999/xhtml')
$qname = $xhtml_ns->qname('div');
とすると、{http://www.w3.org/1999/xhtml}divが返る。
そんな単純なクラスだ。
ちなみに{url}localname っていうのは QName を表記する記法として、James Clarkによって定義されたもの で、一般的によく使われている。
コードは示すまでもないだろうが一応:
package Namespace;
sub new {
my($class, $uri) = @_;
bless \$uri, $class;
}
sub qname {
my($self, $localname) = @_;
"{$$self}$localname";
}
さて、そのクラスのインターフェイスを拡張し、
$xhtml_ns->form; # {http://www.w3.org/1999/xhtml}form
等、任意のメソッドでqname が返るようにしてみよう。
sub AUTOLOAD {
my($self) = @_;
my $localname = our $AUTOLOAD;
$localname =~ s/.*:://o;
"{$$self}$localname";
}
しかしこれだと定義済みのメソッドが邪魔して qname タグや new タグが使えないではないか!
$xhtml_ns->{form}
でもいけるようにしてみよう。これなら任意のタグを表現できるはず・・・、さてどうしたものか。
use overload '%{}' => sub {
my $self = shift;
tie my(%self), $self
\%self;
};
sub TIEHASH {
return $_[0] if ref($_[0]);
shift->new(@_);
}
*FETCH = \&qname;
こんな感じ。$ns->{form}が呼ばれると、use overloadで定義された無名関数が呼び出され、
tieによりTIEHASHが呼び出されてダミーのtied hashが返され、それに対してFETCHが呼び出され、
&FETCHは&qnameの別名なのでqname('form')が呼び出されると。
効率悪そうなことこの上なし。
一応当初予定の
$obj->foo;
$obj->{foo};
両方のインターフェイスは実現できたぞ、と。
これ以上続けても不毛っぽいのでとりあえずこの辺で。多分続かないと思う :-p
カテゴリ
Perlトラックバック(0)
このブログ記事を参照しているブログ一覧: Object? HASH reference? - メソッドと tied ハッシュ 両方のインターフェイスを持つオブジェクト
このブログ記事に対するトラックバックURL: http://www.fs-output.com/rintaro/mt/mt-tb.cgi/17

コメントする