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