コンストラクタとアクセサ自動生成
CLASS
Class::Accessor
Class::Fields
を使います。
以下例、
MyClass.pm
package MyClass;
use strict;
use warnings;
use base qw(Class::Accessor Class::Fields);
use CLASS;
use fields qw( name job _mail );
CLASS->mk_accessors(CLASS->show_fields('Public'));
1;
これだけでMyClassのコンストラクタとfieldsで定義したものへの
アクセサを作ってくれます。便利。
例えばこんな感じで使います。
#! /usr/bin/perl
use strict;
use warnings;
use MyClass;
my $c = MyClass->new;
$c->name('nekokak');
print $c->name,"\n";
$c->job('SE');
print $c->job,"\n";
Class::Fieldsでは_で始まるフィールドはプライベートメソッドとして取り扱われ、
show_fields('Public')メソッドではパブリックなフィールド(_で始まらないフィールド)
が取れてくるので、
CLASS->mk_accessors(CLASS->show_fields('Public'));
とMix-inすることによって
パブリックなフィールドだけアクセサを作ってくれます。
で、Class::Accessor中身がどんな実装になってるか気になったので、
見てみますた。
コアな部分ってこんなのでした。
# Build a closure around $field.
return sub {
my $self = shift;
if(@_) {
return $self->set($field, @_);
}
else {
return $self->get($field);
}
};
sub set {
my($self, $key) = splice(@_, 0, 2);
if(@_ == 1) {
$self->{$key} = $_[0];
}
elsif(@_ > 1) {
$self->{$key} = [@_];
}
else {
$self->_croak("Wrong number of arguments received");
}
}
sub get {
my $self = shift;
if(@_ == 1) {
return $self->{$_[0]};
}
elsif( @_ > 1 ) {
return @{$self}{@_};
}
else {
$self->_croak("Wrong number of arguments received");
}
}
ところで、$self->{'name'}見たいに、インスタンスフィールドに
データを持たせる方法ってどうなの??
って気分で一杯です。
私も普段この方法でやってるのですが、インスタンスが持つデータ量が
少しでも多くなると管理が煩雑になるんですよね。。。
それに、インスタンスフィールドにデータを持たせる方法だと、
コンパイルの段階でエラーに気づかないんですよねぇ。
実行するまでそこのtypoに気づかないのですわ。
例えば、(例えいるのか?)
$c->{'name'}
でアクセスできるフィールドがあったとして、間違って
$c->{'neme'}
と、してしまったと。
でもこれはperl -cでもエラーが見つけられないし、
その行を実行するまで分からないんですよね。
まだ詳細には読んでませんが、Perl Best Practicesでもインスタンスフィールドにデータを持たせるのはどうなのみたいに書いてました。
Perl Best Practicesでは確か、(適当なのでご自分で確認して下さい)
package MyClass2;
use strict;
use warnings;
{
my $name;
my $job;
sub new {
my($class,$self)=(shift,{@_});
bless($self,$class);
$self;
}
sub set_name {
my $self = shift;
$name = shift;
}
sub get_name {
$name;
}
}
1;
こういう風にしてました。
なんとなく俺はこれに賛成ですね。
これを踏まえてプログラム組みたいですねぇ。
CLASSは__PACKAGE__へのエイリアスを行うモジュールです。
__PACKAGE__が好きなかたはそれでどうぞ。