PERLBOT(1) USER COMMANDS PERLBOT(1)
NAME
perlbot - Bag'o Object Tricks For Perl5 (the BOT)
INTRODUCTION
これから示す技とヒントは、インスタンス変数の利用やオブジェク
トとクラスの関係といったことについての、好奇心をそそることを
目指しています。 これを読む方は、オブジェクト指向の定義と方
法論に関する適切な本も、読んだ方がよいでしょう。 このドキュ
メントは、Perl 5 のオブジェクト指向機能の総括的なガイドを目指
すものでもなければ、スタイルガイドとして作られているわけでも
ありません。
Perl のモットーは、ここでも生きています: 「やり方は 1 通りで
はない。」
インスタンス変数
無名の配列や無名のハッシュには、インスタンス変数を入れておく
ことができます。 名前付きパラメータの例もいっしょに示してお
きます。
package Foo;
sub new {
my $type = shift;
my %params = @_;
my $self = {};
$self->{'High'} = $params{'High'};
$self->{'Low'} = $params{'Low'};
bless $self;
}
package Bar;
sub new {
my $type = shift;
my %params = @_;
my $self = [];
$self->[0] = $params{'Left'};
$self->[1] = $params{'Right'};
bless $self;
}
package main;
$a = new Foo ( 'High' => 42, 'Low' => 11 );
print "High=$a->{'High'}\n";
print "Low=$a->{'Low'}\n";
$b = new Bar ( 'Left' => 78, 'Right' => 40 );
print "Left=$b->[0]\n";
print "Right=$b->[1]\n";
Perl manpages Last change: Release 5.0 Patchlevel 00 1
PERLBOT(1) USER COMMANDS PERLBOT(1)
スカラインスタンス変数
無名のスカラは、1 つのインスタンス変数が必要とされるときにだ
け、使うことができます。
package Foo;
sub new {
my $type = shift;
my $self;
$self = shift;
bless \$self;
}
package main;
$a = new Foo 42;
print "a=$$a\n";
インスタンス変数継承
この例では、新しいクラスで、取り込むためのスーパークラスから、
インスタンスを継承する方法を示します。 この継承を行なうには、
コンストラクタ内で新しいオブジェクトに対して、スーパークラスの
コンストラクタを呼び出して継承部分の初期化を行なった後、自分自
身のインスタンス変数の追加を行ないます。
package Bar;
sub new {
my $self = {};
$self->{'buz'} = 42;
bless $self;
}
package Foo;
@ISA = qw( Bar );
sub new {
my $self = new Bar;
$self->{'biz'} = 11;
bless $self;
}
package main;
$a = new Foo;
print "buz = ", $a->{'buz'}, "\n";
print "biz = ", $a->{'biz'}, "\n";
Perl manpages Last change: Release 5.0 Patchlevel 00 2
PERLBOT(1) USER COMMANDS PERLBOT(1)
オブジェクトの関係
以下の例では、オブジェクト間の「包含」および「使用」といわれ
る関係をインプリメントする方法を示します。
package Bar;
sub new {
my $self = {};
$self->{'buz'} = 42;
bless $self;
}
package Foo;
sub new {
my $self = {};
$self->{'Bar'} = new Bar ();
$self->{'biz'} = 11;
bless $self;
}
package main;
$a = new Foo;
print "buz = ", $a->{'Bar'}->{'buz'}, "\n";
print "biz = ", $a->{'biz'}, "\n";
Perl manpages Last change: Release 5.0 Patchlevel 00 3
PERLBOT(1) USER COMMANDS PERLBOT(1)
スーパークラスのメソッドのオーバライド
以下の例は、スーパークラスのメソッドをオーバライドし、オーバ
ライドされた後でそのメソッドを呼び出す方法を示します。
Foo::Inherit クラスを使って、オーバライドされたスーパークラ
スのメソッドが、実際には、どこで定義されているか知らなくても、
そのメソッドを呼び出せるようにしています。
package Buz;
sub goo { print "here's the goo\n" }
package Bar; @ISA = qw( Buz );
sub google { print "google here\n" }
package Baz;
sub mumble { print "mumbling\n" }
package Foo;
@ISA = qw( Bar Baz );
@Foo::Inherit::ISA = @ISA; # オーバライドされたメソ
# ッドのアクセス
sub new { bless [] }
sub grr { print "grumble\n" }
sub goo {
my $self = shift;
$self->Foo::Inherit::goo();
}
sub mumble {
my $self = shift;
$self->Foo::Inherit::mumble();
}
sub google {
my $self = shift;
$self->Foo::Inherit::google();
}
package main;
$foo = new Foo;
$foo->mumble;
$foo->grr;
$foo->goo;
$foo->google;
Perl manpages Last change: Release 5.0 Patchlevel 00 4
PERLBOT(1) USER COMMANDS PERLBOT(1)
SDBM を伴う関係の使用
この例は、SDBM クラスのためのインタフェースを示します。 こ
れは、SDBM クラスと新しいクラス Mydbm との間の「使用」関係を
作ります。
use SDBM_File;
use POSIX;
package Mydbm;
sub TIEHASH {
my $self = shift;
my $ref = SDBM_File->new(@_);
bless {'dbm' => $ref};
}
sub FETCH {
my $self = shift;
my $ref = $self->{'dbm'};
$ref->FETCH(@_);
}
sub STORE {
my $self = shift;
if (defined $_[0]){
my $ref = $self->{'dbm'};
$ref->STORE(@_);
} else {
die "Cannot STORE an undefined key in Mydbm\n";
}
}
package main;
tie %foo, Mydbm, "Sdbm", O_RDWR|O_CREAT, 0640;
$foo{'bar'} = 123;
print "foo-bar = $foo{'bar'}\n";
tie %bar, Mydbm, "Sdbm2", O_RDWR|O_CREAT, 0640;
$bar{'Cathy'} = 456;
print "bar-Cathy = $bar{'Cathy'}\n";
コード再利用の考慮
オブジェクト指向言語の 1 つの強みは、古いコードが新しいコー
ドを使うことが簡単にできるということです。 次の例では、まず
どのようなことがコードの再利用を妨げるかを示して、それから、
どのように再利用を推し進めるかを示します。
最初の例は、「プライベートな」メソッド BAZ() をアクセスする
ために、メソッドを呼び出すのにパッケージ名をすべて付けている
クラスを示します。 次の例で、この BAZ() をオーバライドする
ことができないことを示します。
Perl manpages Last change: Release 5.0 Patchlevel 00 5
PERLBOT(1) USER COMMANDS PERLBOT(1)
package FOO;
sub new { bless {} }
sub bar {
my $self = shift;
$self->FOO::private::BAZ;
}
package FOO::private;
sub BAZ {
print "in BAZ\n";
}
package main;
$a = FOO->new;
$a->bar;
さて、BAZ() をオーバライドしてみましょう。 FOO::bar()が
GOOP::BAZ() を呼ぶようにしたいのですが、FOO::bar() では、明
示的に FOO::private::BAZ() を呼んでいるため、これができませ
ん。
package FOO;
sub new { bless {} }
sub bar {
my $self = shift;
$self->FOO::private::BAZ;
}
package FOO::private;
sub BAZ {
print "in BAZ\n";
}
package GOOP;
@ISA = qw( FOO );
sub new { bless {} }
sub BAZ {
print "in GOOP::BAZ\n";
}
package main;
$a = GOOP->new;
$a->bar;
Perl manpages Last change: Release 5.0 Patchlevel 00 6
PERLBOT(1) USER COMMANDS PERLBOT(1)
再利用可能なコードを作るためには、クラス FOO::private の階層
をなくして、クラス FOO を修正しなければなりません。 次の例
で、メソッド FOO::BAZ() の代わりに GOOP::BAZ() を呼べるよう
にする再利用可能なクラス FOO を示します。
package FOO;
sub new { bless {} }
sub bar {
my $self = shift;
$self->BAZ;
}
sub BAZ {
print "in BAZ\n";
}
package GOOP;
@ISA = qw( FOO );
sub new { bless {} }
sub BAZ {
print "in GOOP::BAZ\n";
}
package main;
$a = GOOP->new;
$a->bar;
クラスコンテキストとオブジェクト
パッケージとクラスのコンテキストの問題を解決するために、オブ
ジェクトを使います。 メソッドが必要とするものはすべて、オブ
ジェクトを通じて利用するか、メソッドへの引数として渡すように
しなければなりません。
クラスには、メソッドが使用する静的なデータやグローバルなデー
タを用意することがあります。 サブクラスで、このデータを新し
いデータでオーバライドしたいこともあるでしょう。 このような
ときに、サブクラスでは新しいデータを探す方法を知ることができ
ません。
この問題は、メソッドのコンテキストを定義するために、オブジェ
クトを使うことで解決することができます。 データへのリファレ
ンスを探すために、メソッドにオブジェクトを覗かせます。 別解
として、メソッドに追いかけさせ (「これは、私のクラスのものか、
それともサブクラスのものなのか。 いったい、どのサブクラスの
ものか。」)るものですが、不便で、遺物のようなものにしかなら
ないでしょう。 メソッドに対して、オブジェクトにデータがどこ
にあるのかを言わせればよいでしょう。
Perl manpages Last change: Release 5.0 Patchlevel 00 7
PERLBOT(1) USER COMMANDS PERLBOT(1)
package Bar;
%fizzle = ( 'Password' => 'XYZZY' );
sub new {
my $self = {};
$self->{'fizzle'} = \%fizzle;
bless $self;
}
sub enter {
my $self = shift;
# %Bar::fizzle を使うべきか、%Foo::fizzle を
# 使うべきかを考えてはいけません。 オブジェ
# クトの方でもう分かっていますから、単に尋く
# だけです。
#
my $fizzle = $self->{'fizzle'};
print "The word is ", $fizzle->{'Password'}, "\n";
}
package Foo;
@ISA = qw( Bar );
%fizzle = ( 'Password' => 'Rumple' );
sub new {
my $self = Bar->new;
$self->{'fizzle'} = \%fizzle;
bless $self;
}
package main;
$a = Bar->new;
$b = Foo->new;
$a->enter;
$b->enter;
Perl manpages Last change: Release 5.0 Patchlevel 00 8