題名¶
Moose::Manual::Construction - Mooseを使ったオブジェクトの生成(と破棄)
コンストラクタはどこにありますか¶
自分のクラスにはnew()メソッドを定義しないでください!
use MooseしたクラスはMoose::Objectのサブクラスになるのですが、newメソッドはこのMoose::Objectが用意してくれます。Moose::Manual::BestPracticesのおすすめ通りにクラスを不変化した場合は、そのクラス専用のnewメソッドがクラスの中に実際に「インライン展開」されます。
オブジェクトの生成とアトリビュート¶
Mooseが提供するコンストラクタはアトリビュートに対応する(実際にはアトリビュートのinit_argに対応する)名前付きパラメータのハッシュないしハッシュリファレンスを受け付けます。これもまたMooseを使うとクラスが「どのように」実装されているか心配しなくてよくなる理由のひとつです。クラスを定義しさえすればオブジェクトを生成できるようになるのです!
オブジェクト生成時の割り込み¶
Mooseを使うとオブジェクト生成時に割り込みをかけることもできます(オブジェクトの状態を検証したり、ログを取ったり、おそらくハッシュ(リファレンス)以外のコンストラクタ引数を許すようにもできます)。そうする場合は、BUILDメソッドやBUILDARGSメソッドを作ってください。
これらのメソッドがクラスに存在している場合、Mooseはオブジェクト生成プロセスの途中でこれらのメソッドを呼ぶよう手配してくれます。
BUILDARGS¶
BUILDARGSメソッドは、オブジェクトが生成される「前に」、クラスメソッドとして呼ばれます。BUILDARGSメソッドは、newに渡されたすべての引数を「そのままの形で」受け取り、ハッシュリファレンスを返すことが期待されています。このハッシュリファレンスはオブジェクトを生成するときに使うので、アトリビュート名(というかinit_arg)に対応したキーを入れておくようにしてください。
BUILDARGSは、ハッシュ(リファレンス)以外の呼び出し方に対応させるときによく使われます。たとえば、PersonクラスはPerson->new($ssn)のように社会保障番号ひとつで呼べるようにしたい場合があるかもしれません。
この場合、BUILDARGSメソッドがないと、Mooseは(ハッシュまたはハッシュリファレンスを期待しているので)エラーを発生させますが、BUILDARGSメソッドを使うとこの呼び出し方に対応できます。
around BUILDARGS => sub {
my $orig = shift;
my $class = shift;
if ( @_ == 1 && ! ref $_[0] ) {
return $clas->$orig( ssn => $_[0] );
}
else {
return $class->$orig(@_);
}
};
$class-$orig>を呼んでいることに注意してください。これは親クラスのメソッドを呼び出すことによりMoose::Objectにデフォルトで用意されているBUILDARGSを呼ぶものです。このメソッドを使うとハッシュリファレンスとただのハッシュを区別してくれます。
BUILD¶
BUILDメソッドはオブジェクトが生成された「あとに」呼ばれます。BUILDメソッドの使い方はいくつかありますが、もっともよくあるのは、オブジェクトの状態が有効かどうかチェックするものです(型を使えば個々のアトリビュートの検証はできますが、オブジェクト全体の状態についてはその方法では検証できません)。
sub BUILD {
my $self = shift;
if ( $self->country_of_residence eq 'USA' ) {
die 'All US residents must have an SSN'
unless $self->has_ssn;
}
}
BUILDメソッドのほかの使い方としては、オブジェクトを生成したときのログ取りやトラッキングがあげられます。
sub BUILD {
my $self = shift;
debug( 'Made a new person - SSN = ', $self->ssn, );
}
ここでは使用していませんが、BUILDメソッドは作成されたオブジェクトだけではなく、newに渡された元の引数(もしBUILDARGSをオーバーライドしているなら、BUILDARGSの戻り値)が渡されます。デフォルトで提供されている初期化や型変換の仕組み以外の操作が必要な場合は便利かもしれません。
BUILDと親クラス¶
継承階層に複数のBUILDメソッドがある場合、Perlのふつうのメソッドとは相互作用の仕方が異なるので、決して$self->SUPER::BUILDは呼ばないようにしてください。
Mooseは、オブジェクトを生成するとき、階層内にあるすべてのBUILDメソッドを「親から子の順番で」呼ぶよう手配します(最初は驚くかもしれませんが、通常のメソッド継承の順番とは逆なのです)。
このようになっているのは、BUILDメソッドはクラスの制約の特殊性を増すことにしか使えないため、もっとも抽象的なBUILDから呼んでいく方が理にかなっているからです(なお、Perl 6もそのようになっています)。
オブジェクトの破棄¶
Mooseを使うと、オブジェクトを破棄するときもDEMOLISHメソッドで割り込みをかけられます。BUILDの場合と同じく、明示的に$self->SUPER::DEMOLISHを呼ぶことは決してしないでください。Mooseは階層内のすべてのDEMOLISHメソッドを、もっとも具体的なクラスからもっとも抽象的なクラスの順に呼ぶよう手配します。
それぞれのDEMOLISHメソッドは1つの引数をうけとります。
ただし、たいていの場合はPerlに組み込まれているガベージコレクションで十分です。DEMOLISHメソッドを用意する必要はありません。
オブジェクト破棄時のエラー処理¶
オブジェクト破棄時の動作とPerlのグローバル変数$@や$?との連携は時々わかりにくい副作用を及ぼします。
オブジェクト破棄時にMooseは必ず$?をローカル化します。これはもしデストラクタでsystemを使用してても、exitの値は保護されるということになります。
オブジェクト破棄時にMooseは必ず$@もローカル化します。ただし、オブジェクトのDEMOLISHメソッドが例外を投げた場合はMooseは明示的に再度同じ例外を投げます。
もしこの動作仕様があなたの要求と会わない場合は、デフォルトのMoose::Objectの代わりに自前のDESTROOYメソッドを用意する必要があります。このようにすると例えば$@の値を保持したままオブジェクト破棄時に起こったエラーのスタックをキャプチャすることができます。
作者¶
Dave Rolsky <autarch@urth.org>
コピーライト & ライセンス¶
Copyright 2009 by Infinity Interactive, Inc.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.