コンストラクタとアクセサ自動生成2

コンストラクタとアクセサ自動生成では

Class::AccessorとClass::Fields

を多重継承してますが、Class::FieldsはメソッドをEXPORTしてるので、
通常にuseするだけでも使えます。
なので、


package MyClass3;
use strict;
use warnings;
use base qw(Class::Accessor);
use Class::Fields;
use CLASS;
use fields qw( name job _mail );
CLASS->mk_accessors(CLASS->show_fields('Public'));
1;

これでもOKです。
多重継承させてません。

で、多重継承をさせずにMix-inさせる手法ですが、
Class::Fieldsでは
以下のようにしてます。


require Exporter;
@ISA = qw(Exporter);
# is_* will push themselves onto @EXPORT
@EXPORT = qw( field_attrib_mask
field_attribs
dump_all_attribs
show_fields
is_public
is_private
is_protected
is_inherited
is_field
);

こうすることで各メソッドをEXPORTしてるわけですが、
Expoter::Liteモジュールをつかえば、


use Expoter::Lite;
@EXPORT = qw( field_attrib_mask
field_attribs
dump_all_attribs
show_fields
is_public
is_private
is_protected
is_inherited
is_field
);

こんな感じで書けます。

で、Exporter::Liteの中身をみたら、

importメソッドをEXPORTしてました。
にゃるほど〜〜〜って感じです。

で、メソッドをEXPORTする時の注意点ですが、

EXPORTするメソッド内でそのメソッドが元々属するクラスの
メソッド(EXPORTされていないメソッド)を呼ぶ場合ですね。
継承ツリーの中にEXPORTされていないメソッドは見つけることができないので、
(継承してないから当然ですね)
例外が発生します。

例えばこんなのかな。
電話をかけて話す猫がいたとします。
Telクラスで電話をかけて、
Speekクラスでしゃべります。
こんなサンプルでよいのか激しく疑問w
Telクラスは
telメソッドをエクスポートし、
Speekクラスは
speekメソッドをエクスポートしてます。

./neko.pl


#! /usr/bin/perl
use strict;
use warnings;
use Neko;
my $n = Neko->new;
$n->tel;
$n->speek;

./Neko.pm


package Neko;
use strict;
use warnings;
use Speek;
use Tel;
sub new {
my($class,$self)=(shift,{@_});
bless($self,$class);
$self;
}
1;

./Tel.pm


package Tel;
use strict;
use warnings;
use vars qw(@ISA @EXPORT);
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(
tel
);
sub new {
my($class,$self)=(shift,{@_});
bless($self,$class);
$self;
}
sub tel {
my $self = shift;
my $no = shift->get_phone_no;
print $no;
}
sub get_phone_no {
my $self = shift;
return "090-000-0000";
}
1;

./Speek.pm


package Speek;
use strict;
use warnings;
use vars qw(@ISA @EXPORT);
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(
speek
);
sub new {
my($class,$self)=(shift,{@_});
bless($self,$class);
$self;
}
sub speek {
my $self = shift;
my $no = $self->get_word;
print $no;
}
sub get_word {
my $self = shift;
return "Hello";
}
1;

ここでの注目は
Telクラスのget_phone_noメソッドと
Speekクラスのget_wordメソッドです。
こいつらはEXPORTされてません。

この状態でneko.plを実行すると。

Can't locate object method "get_phone_no" via package "Neko" at Tel.pm line 21.

と例外が発生します。

Neko.pmからはEXPORTされていないget_phone_noは見えないですからね。

で、どうするかというと、

Tel.pmのtelメソッドを以下のように修正します。


sub tel {
my $self = shift;
my $no = get_phone_no($self);
print $no;
}

すると次は

Can't locate object method "get_word" via package "Neko" at Speek.pm line 22.

こんな例外が発生します。
Speekクラスのget_wordメソッドもEXPORTしてないですからね。

で、こんな感じで修正します。


sub speek {
my $self = shift;
my $no = get_word($self);
print $no;
}

するとうごきます。

で、

get_phone_no($self);

こんなのがいやだと。
なんでOOPやってるのに関数チックな呼び出しをするのかと
じゃあこうしませう。


sub tel {
my $self = shift;
my $no = __PACKAGE__->get_phone_no;
print $no;
}

パッケージ修飾でメソッドを呼び出します。

ちょっと長くなりましたが、以上こんな感じでいかがでしょうか?