既存の特異メソッドモジュール
Perlで特異メソッドでは「標準モジュールにも特異メソッドを実現するものはない」と書いたが,そういえばPerl 5.10.0から標準モジュールになったObject::Accessorというものがあることを思い出した。これは直接特異メソッドを定義するのではないが,振る舞いとしては特異メソッドそのものである。実際,Class::Monadicもadd_field()というアクセサを作成する機能を提供している。
Object::AccessorのSYNOPSISより:
### using the object as base class package My::Class; use base 'Object::Accessor'; $obj = My::Class->new; # create base object $bool = $obj->mk_accessors('foo'); # create accessors, etc...
しかし,その実装はClass::Monadicとはまったく異なる。
Class::Monadicが実際に新しいクラス(シンボルテーブル)を作成するのに対し,Object::Accessorでは特異メソッドの処理をAUTOLOADで行っている。したがって,アクセサの定義は早いが呼び出しは非常に遅い。また,この機能を使うためにはObject::Accessorを継承しなければならず,既存のクラスに対して特異メソッドを定義することはできない。
なお,CPANにあるClass::Componentも特異メソッドを定義するコンポーネントを提供している*1。こちらの実装はClass::Monadicと同様であり,新しいクラスを作成してそのクラスにメソッドを定義している。
使用法は以下の通り:
#!perl -w use strict; { package MyClass; use Class::Component; __PACKAGE__->load_components(qw(Autocall::SingletonMethod)); package MyComponent; use base qw(Class::Component::Plugin); sub hello{ print "Hello, world!\n"; } } my $o = MyClass->new(); $o->register_method( hello => 'MyComponent', ); $o->hello(); __END__
これはその場で特異メソッドを定義するというより,オブジェクトに特異的にコンポーネントを組み込むという感じだろうか。これは以下に示すように,Class::Monadic->inject_base()に近い機能であるように見える:
#!perl -w use strict; use Class::Monadic; { package MyClass; sub new{ bless {}, shift; } package MyComponent; sub hello{ print "Hello, world!\n"; } } my $o = MyClass->new(); Class::Monadic->initialize($o)->inject_base('MyComponent'); $o->hello(); __END__
いずれにせよ実装のための基本的な考え方は同じである。