Class::Struct
もう少し現実的なアクセサメソッドの自動生成をするには……、とラクダ本を読んでみたら、標準モジュール Class::Struct が紹介されていました。C言語の構造体のような、簡単なデータクラスを作ってくれるモジュールです。
簡単な、といっても、かなり柔軟に作成できるので「perldoc Class::Struct」を読むとワクワクしてきます♪
まずは、昨日書いた Person クラスを、Class::Struct を使って書き直してみます。
package Person;
use Class::Struct;
struct Person => {
name => '$', # スカラー型
age => '$', # スカラー型
};
sub introduce {
my $self = shift;
print "I am " . $self->name();
print ", " . $self->age() . " years old.\n";
}
package main;
$man = Person->new(name => "Somebody", age => 0);
$man->introduce();
$man->name("Taro");
$man->age(10);
$man->introduce();
昨日のコードに比べるとずいぶんとスッキリしましたね。(^_^)
「use Class::Struct」してモジュールを取り込むと、「struct」という関数がエクスポートされて使えるようになります。
struct 関数に、クラス名と、クラス属性・属性の型のハッシュリファレンスを渡すとコンストラクタ new と、各属性に対するアクセサメソッドを自動生成してくれます。ちなみに、クラス名を省略すると暗黙的に現在のパッケージ名が使われるとのこと。
struct 関数に渡すハッシュリファレンスは、クラスが持つ属性名がキー、その属性の型が値になります。属性の型は例えばスカラーなら '$'、配列なら '@'、ハッシュなら '%' のように、文字列で指定します。属性の型にクラス名を指定すると、そのクラス(かサブクラス)のオブジェクトリファレンスを入れられるようになります。
コンストラクタ new を呼ぶときに、属性を初期化する事ができます。(モジュール側で初期値を決めるにはどうすればいいんだろう)
もうちょっと複雑なコードを書いてみます。
package Person;
use Class::Struct;
struct Person => {
name => '$',
age => '$',
friends => '@',
mother => 'Person',
father => 'Person',
};
sub introduce {
my $self = shift;
print "I am " . $self->name;
print ", " . $self->age . " years old.\n";
if (ref($self->friends) eq "ARRAY") {
print "Friends: " . join(" ", @{$self->friends}) . "\n";
}
$self->mother->introduce() if $self->mother;
$self->father->introduce() if $self->father;
}
package main;
my $taro = Person->new(
name => "Taro",
age => 10,
friends => ["Kenji", "Yuko"],
mother => Person->new(
name => "Taro's mother",
age => 36,
friends => ["Mika", "Kei"],
),
father => Person->new(
name => "Taro's father",
age => 38,
friends => ["Shota", "Hikaru"],
),
);
$taro->introduce();
Person クラスに新しく friends、mother、father という属性を増やしました。friends は友達の名前の配列、mother は母親の Person オブジェクト、father は父親の Person オブジェクトです。ツリー構造ですね。
introduce メソッドで友達の名前を挙げるようにして、父親と母親も再帰的に紹介させるようにしました。
package main では name "Taro" の Person オブジェクトを生成していますが、mother と father に新しい Person オブジェクトを直接生成して渡しています。ここでは父母までで止めましたが、書こうと思えば太郎の母の母(太郎の祖母)や父の父の父(曽祖父)など、いくらでも再帰的に書く事ができます。ツリー構造がそのまま書けて面白いですね。
以下が実行結果です。
I am Taro, 10 years old. Friends: Kenji Yuko I am Taro's mother, 36 years old. Friends: Mika Kei I am Taro's father, 38 years old. Friends: Shota Hikaru
上手く出力できました。
実は、最初 use Class::Sturct と typo してしまって、エラーの原因がわからず30分ほど悩んでしまいました。はずかし(^_^;;