汎用的なコンストラクタの雛形
汎用的なコンストラクタの雛形を提示しておきます。汎用的なコンストラクタの雛形はちょっと難しいです。
1. 汎用的なコンストラクタの指針
汎用的なコンストラクタは、クラスから呼ばれたときだけではなくて、オブジェクトから呼び出された場合も考慮に入れる必要があります。
クラスから呼ばれた場合と
my $book = Book->new;
オブジェクトから呼ばれた場合の
my $book2 = $book->new
の両方に対応する。
またもうひとつの指針として、コンストラクタと初期化処理は分離するということが挙げられます。初期化用のinitメソッドを作成してあげます。
2. 汎用的なコンストラクタの作成
以下が汎用的なコンストラクタの雛形です。
sub new { my $proto = shift; my $class = ref $proto || $proto; my $self = {}; bless $self, $class; $self->init(@_); return $self; } sub init { my ($self, @args) = @_; # 追加で行いたい処理 }
3. オブジェクトからクラス名を取り出す処理
この部分がわかりにくいと思います。
my $proto = shift; my $class = ref $proto || $proto;
これは何をやっているかというと、$proto がオブジェクトだった場合には、ref関数を使って関連付けられているクラス名を取り出します。
そうでない場合は、クラス名をそのまま使用するということをやっています。ref関数に文字列(クラス名)が渡された場合は、偽値が返るので、|| の右側が実行されます。
そういうわけで、クラス名から呼ばれても、オブジェクトから呼ばれても、$classにはクラス名が入ることになります。
4. 初期化処理を分離する
初期化処理を分離しているのが以下の部分です。初期化を行う場合は、bless 関数で先にオブジェクトを作成しておいてあげます。そしてそのオブジェクトから、initメソッドを呼び出します。
ちょっとわかりにくいですが、慣れましょう。同じクラスのメソッドを呼び出すには、オブジェクトつまり、bless された $self から呼び出す必要があるのです。
my $self = {}; bless $self, $class; $self->init(@_);
5. なぜこのように作成する必要があるのか?
それはきちんとはまだいいません。継承のところで取り上げることにします。このようにオブジェクトを作成しておかないと、継承をしようとしたときに面倒な問題が発生するとだけいっておきます。