題名¶
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 {
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.