コンストラクタの遅延
ふと思いついて、CPAN検索したらいくつか既存モジュールあったけど、 英語読むのがめんどくさくてソースも長くて読むのがめんどくさかったので、 試しもせずに車輪の再発明をしてみました。
要はYet Another な Object::Realize::Later や Class::LazyObject です。
コンストラクタのコストが高いオブジェクトってありますよね、それらに対して、 使うかどうか分からないけど、一応newしておきたい。 アプリの初期化時にnewしたいけど、初期化でもたつきたくないので、実際に使う時までコンストラクタを遅延したい。 なんていう時に使います。
使い方は簡単
use Class::Lazy;
my $foo = YourHeavyClass->lazy::new(@args);
これだけ。つまりコンストラクタメソッドの前に lazy:: をつけるだけです。
あとは、この $foo に対してメソッドを呼び出した時点でフックされてコンストラクタ実行され、 その返値に対してメソッドが実行されます。 それ以降は $foo自体がすでにきちんと初期化されたオブジェクト(コンストラクタの返値)になっているので、 通常通りの動作をします。
package Class::Lazy;
use strict;
use warnings;
our $VERSION = '0.01';
sub AUTOLOAD {
if(@{$_[0]} > 1) {
my($caller, $constructor, $class, @args) = @{$_[0]};
my $thing = $class->$constructor(@args)
or die qq{Can't construct "$class" object with "$constructor"}
. qq{at $caller->[1] line $caller->[2].\n};
@{$_[0]} = $thing;
}
$_[0] = $_[0][0]; # realize it!
our $AUTOLOAD =~ s/^.*:://o;
my $method = $_[0]->can($AUTOLOAD);
goto $method if $method;
# method not found!
shift->$AUTOLOAD(@_); # die?
}
# Override UNIVERSAL methods.
sub isa { $_[0][2]->isa($_[1]) };
sub can { $_[0][2]->can($_[1]) };
# Do not have to AUTOLOAD this.
sub DESTROY { undef; }
###########################################################################
package lazy;
sub AUTOLOAD {
my $constructor = substr(our($AUTOLOAD), 6); # 6 == length('lazy::')
bless [[caller()], $constructor, @_], 'Class::Lazy';
}
__END__
一度初期化されるまで、ref()の値が本来のものと違うとか、 overload されたオブジェクトでoverloadが有効にならないとか、 いろいろ制限はありますが、素直なメソッドによるオブジェクト操作だけなら有用なんではないかと思います。
2007/07/27追記
オーバーロードに対応して、もうちょっときちんとしたものをTracのプロジェクトページ に置きました。
カテゴリ
Perlトラックバック(0)
このブログ記事を参照しているブログ一覧: コンストラクタの遅延
このブログ記事に対するトラックバックURL: http://www.fs-output.com/rintaro/mt/mt-tb.cgi/19

コメントする