=encoding euc-jp =head1 NAME =begin original perltooc - Tom's OO Tutorial for Class Data in Perl =end original perltooc - トムによる Perl のクラスデータのためのオブジェクト指向チュートリアル =head1 DESCRIPTION =begin original When designing an object class, you are sometimes faced with the situation of wanting common state shared by all objects of that class. Such I act somewhat like global variables for the entire class, but unlike program-wide globals, class attributes have meaning only to the class itself. =end original オブジェクトクラスを宣言するとき、共通の状態をクラスの全てのオブジェクトが 共有したい状況に直面することがあります。 そのような I<クラス属性> は、いくぶん、クラス全体のグローバル変数のように はたらきます。 ですが、プログラム全体のグローバル変数とは違い、クラス属性は、クラス それ自身にとってのみグローバルです。 =begin original Here are a few examples where class attributes might come in handy: =end original クラス属性が役に立つ例がいくつかあります。 =over 4 =item * =begin original to keep a count of the objects you've created, or how many are still extant. =end original 生成したオブジェクトの数を保っておくために。 また、まだいくつあるのかを数えておくために。 =item * =begin original to extract the name or file descriptor for a logfile used by a debugging method. =end original デバッグメソッドで使われるログファイルの名前か、ファイル識別子を 引き出すために。 =item * =begin original to access collective data, like the total amount of cash dispensed by all ATMs in a network in a given day. =end original 全体的なデータにアクセスするために。 たとえば、与えられた日の、ネットワークの全 ATM で支払われた現金の 総金額のようなものにアクセスするために。 =item * =begin original to access the last object created by a class, or the most accessed object, or to retrieve a list of all objects. =end original クラスによって、最後に作られたオブジェクトにアクセスするために、 また、もっともアクセスされたオブジェクトにアクセスするために、 また、すべてのオブジェクトのリストを検索するために。 =back =begin original Unlike a true global, class attributes should not be accessed directly. Instead, their state should be inspected, and perhaps altered, only through the mediated access of I. These class attributes accessor methods are similar in spirit and function to accessors used to manipulate the state of instance attributes on an object. They provide a clear firewall between interface and implementation. =end original 本当のグローバル変数とは違って、クラス属性は直接にアクセスされるべきでは ありません。 直接にアクセスされるべきではありませんが、クラス属性の状態は 調べられるべきですし、たぶん、変更もされるべきです。 ただし、I<クラスメソッド> を仲介して、アクセスすることを通してのみです。 クラス属性のアクセサメソッドは、気持ちと、機能の上では、 オブジェクトのインスタンス属性の状態を操作するのに使われるアクセサに 似ています。 これらは、インターフェースと実装の間に透明なファイアウォールを提供します。 =begin original You should allow access to class attributes through either the class name or any object of that class. If we assume that $an_object is of type Some_Class, and the &Some_Class::population_count method accesses class attributes, then these two invocations should both be possible, and almost certainly equivalent. =end original クラス属性へのアクセスは、クラスの名前か、クラスのオブジェクトのどちらを 通してもできるようにすべきです。 $an_object が、Some_Class の型のもので、 &Some_Class::population_count メソッドがクラス属性にアクセスするとします。 そうすると、2 つの呼び出しが両方とも可能であるべきです。 そして、もちろん、ほとんど同じであるべきです。 Some_Class->population_count() $an_object->population_count() =begin original The question is, where do you store the state which that method accesses? Unlike more restrictive languages like C++, where these are called static data members, Perl provides no syntactic mechanism to declare class attributes, any more than it provides a syntactic mechanism to declare instance attributes. Perl provides the developer with a broad set of powerful but flexible features that can be uniquely crafted to the particular demands of the situation. =end original 疑問があります。 このメソッドがアクセスする、その状態をどこに置いておくのでしょうか? C++ のような、より厳格な言語とは違って、Perlには静的なデータメンバと 呼ばれる場所はありません。 Perl は、クラス属性を宣言するのに、総合のメカニズムはまったく提供しません。 インスタンス属性を宣言する総合のメカニズムしかありません。 Perl は開発者に、特殊な状況の要求にも、うまく作ることのできる、 強力ですが、柔軟な、大まかなセットを提供します。 =begin original A class in Perl is typically implemented in a module. A module consists of two complementary feature sets: a package for interfacing with the outside world, and a lexical file scope for privacy. Either of these two mechanisms can be used to implement class attributes. That means you get to decide whether to put your class attributes in package variables or to put them in lexical variables. =end original Perlのクラスは、典型的にモジュールに実装されます。 モジュールは、2 つの相補的な特徴の組合わせで、できています:外の世界との インターフェースのためのパッケージと、プライバシーのためのレキシカルな ファイルスコープのセットです。 これらの 2 つのメカニズムの両方を、クラス属性の実装に使うことができます。 このことは、すなわち、クラス属性をパッケージ変数に置くか、 レキシカル変数に置くかを決めることができるということです。 =begin original And those aren't the only decisions to make. If you choose to use package variables, you can make your class attribute accessor methods either ignorant of inheritance or sensitive to it. If you choose lexical variables, you can elect to permit access to them from anywhere in the entire file scope, or you can limit direct data access exclusively to the methods implementing those attributes. =end original また、これらは、作るのにあたっての唯一の判断ではありません。 パッケージ変数を選んだとしても、クラス属性アクセサメソッドに、継承を 無視させるか、継承に反応させることもできます。 レキシカル変数を選んだとしても、まったく、ファイルスコープの中の どこからでも、クラス属性にアクセスすることを許すこともできますし、また、 直接データにアクセスするのを、 排他的に、それらの属性を実装するメソッドだけに制限することも出来ます。 =head1 Class Data in a Can (缶の中のクラスデータ) =begin original One of the easiest ways to solve a hard problem is to let someone else do it for you! In this case, Class::Data::Inheritable (available on a CPAN near you) offers a canned solution to the class data problem using closures. So before you wade into this document, consider having a look at that module. =end original 難しい問題を解決するための、もっとも簡単な方法の一つは、誰か他の人に 問題を解決させることです! この場合、Class::Data::Inheritable (お近くの CPAN で利用できます)が、 クロージャを使うクラスデータの問題の決まりきった解決法を提供します。 ですので、このドキュメントを苦労して読み進める前に、 Class::Data::Inheritable モジュールを見ることを検討してください。 =head1 Class Data as Package Variables (パッケージ変数としてクラスデータを) =begin original Because a class in Perl is really just a package, using package variables to hold class attributes is the most natural choice. This makes it simple for each class to have its own class attributes. Let's say you have a class called Some_Class that needs a couple of different attributes that you'd like to be global to the entire class. The simplest thing to do is to use package variables like $Some_Class::CData1 and $Some_Class::CData2 to hold these attributes. But we certainly don't want to encourage outsiders to touch those data directly, so we provide methods to mediate access. =end original Perlのクラスは、本当に、ただのパッケージなので、クラス属性を持つのに、 パッケージ変数を使うのはもっとも自然な選択です。 つまり、パッケージに、単純にそれ自身のクラス属性をもたせるのです。 例えば、クラス全体にグローバルであるような、異なった属性がいくつか必要な Some_Class というクラスがあるとします。 もっとも簡単なのは、$Some_Class::CData1 や$Some_Class::CData2 のような パッケージ変数を使い、これらの属性を持たせることです。 ですが、もちろん部外者がこれらのデータディレクトリに触ることを 勧めたくはありません。 ですので、アクセスを仲介するメソッドを提供します。 =begin original In the accessor methods below, we'll for now just ignore the first argument--that part to the left of the arrow on method invocation, which is either a class name or an object reference. =end original 下の、アクセサメソッドで、今のところ、第一引数 -- メソッド呼び出しの矢印の 左の部分で、クラスの名前か、オブジェクトリファレンス -- を、無視しています。 =begin original package Some_Class; sub CData1 { shift; # XXX: ignore calling class/object $Some_Class::CData1 = shift if @_; return $Some_Class::CData1; } sub CData2 { shift; # XXX: ignore calling class/object $Some_Class::CData2 = shift if @_; return $Some_Class::CData2; } =end original package Some_Class; sub CData1 { shift; # XXX: クラス/オブジェクト呼び出しを無視します $Some_Class::CData1 = shift if @_; return $Some_Class::CData1; } sub CData2 { shift; # XXX: クラス/オブジェクト呼び出しを無視します $Some_Class::CData2 = shift if @_; return $Some_Class::CData2; } =begin original This technique is highly legible and should be completely straightforward to even the novice Perl programmer. By fully qualifying the package variables, they stand out clearly when reading the code. Unfortunately, if you misspell one of these, you've introduced an error that's hard to catch. It's also somewhat disconcerting to see the class name itself hard-coded in so many places. =end original このテクニックは、非常に読みやすく、普通のPerlプログラマにとってさえ、 完全に直接です。 パッケージ変数を完全に修飾することで、コードを読むときに、はっきりと、 目立ちます。 不運なことに、もし、これらの一つでも、スペルを間違えたら、捕まえがたい エラーを持ち込むことになります。 また、クラスの名前自身を多くの場所にハードコードしているのを見るのは、 いくぶんイライラもさせます。 =begin original Both these problems can be easily fixed. Just add the C pragma, then pre-declare your package variables. (The C operator will be new in 5.6, and will work for package globals just like C works for scoped lexicals.) =end original この 2 つの問題は、両方とも簡単に修正できます。 C プラグマを加え、それから、パッケージ変数を先に 宣言するだけです。 (C 演算子は、5.6 の、新しいものです。 C がスコープされたレキシカル変数に働くのと同じように、パッケージの グローバル変数に働きます。) =begin original package Some_Class; use strict; our($CData1, $CData2); # our() is new to perl5.6 sub CData1 { shift; # XXX: ignore calling class/object $CData1 = shift if @_; return $CData1; } sub CData2 { shift; # XXX: ignore calling class/object $CData2 = shift if @_; return $CData2; } =end original package Some_Class; use strict; our($CData1, $CData2); # our() is new to perl5.6 sub CData1 { shift; # XXX: クラス/オブジェクト呼び出しを無視します $CData1 = shift if @_; return $CData1; } sub CData2 { shift; # XXX: クラス/オブジェクト呼び出しを無視します $CData2 = shift if @_; return $CData2; } =begin original As with any other global variable, some programmers prefer to start their package variables with capital letters. This helps clarity somewhat, but by no longer fully qualifying the package variables, their significance can be lost when reading the code. You can fix this easily enough by choosing better names than were used here. =end original 他のどのグローバル変数とも同じように、 これらパッケージ変数を大文字で始めるのを好むプログラマがいます。 このことは、いくぶん明瞭さを助けますが、パッケージ変数がまったく 修飾されていないので、コードを読むときにその重要性が失われるかもしれません。 これを修正するのは簡単で、ここで使われているよりも、もっと良い名前を選べば 事足ります。 =head2 Putting All Your Eggs in One Basket (卵をみんな、一つのバスケットに置く) =begin original Just as the mindless enumeration of accessor methods for instance attributes grows tedious after the first few (see L), so too does the repetition begin to grate when listing out accessor methods for class data. Repetition runs counter to the primary virtue of a programmer: Laziness, here manifesting as that innate urge every programmer feels to factor out duplicate code whenever possible. =end original ちょうど、インスタンス属性のアクセサメソッドを思慮なく列挙するのが、 最初の数回の後には、飽き飽きするものになっていくように(L を参照)、 クラスデータのアクセサメソッドをリストするときも、 同じことのくり返しに、非常にイライラしてくるでしょう。 くり返しは、プログラマの主要な美徳、不精に反します。 ここでは、あらゆるプログラマが感じる生まれつきの衝動が、 出来るかぎりコードの二重化を睨むものとして現れます。 =begin original Here's what to do. First, make just one hash to hold all class attributes. =end original 次のようにすべきです。 最初に、全てのクラス属性を持つハッシュをただ一つ、作ります。 package Some_Class; use strict; our %ClassData = ( # our() is new to perl5.6 CData1 => "", CData2 => "", ); =begin original Using closures (see L) and direct access to the package symbol table (see L), now clone an accessor method for each key in the %ClassData hash. Each of these methods is used to fetch or store values to the specific, named class attribute. =end original クロージャ(L 参照)を使って、パッケージのシンボルテーブル (L 参照)に直接にアクセスします。 さて、%ClassData ハッシュの中のそれぞれのキーごとに、アクセサメソッドを クローニングします。 これらのメソッドは、値を持ってくるか、特定の指定されたクラス属性に値を 格納するために使われます。 =begin original for my $datum (keys %ClassData) { no strict "refs"; # to register new methods in package *$datum = sub { shift; # XXX: ignore calling class/object $ClassData{$datum} = shift if @_; return $ClassData{$datum}; } } =end original for my $datum (keys %ClassData) { no strict "refs"; # パッケージに新しいメソッドを登録するために *$datum = sub { shift; # XXX: クラス/オブジェクトの呼出を無視する $ClassData{$datum} = shift if @_; return $ClassData{$datum}; } } =begin original It's true that you could work out a solution employing an &AUTOLOAD method, but this approach is unlikely to prove satisfactory. Your function would have to distinguish between class attributes and object attributes; it could interfere with inheritance; and it would have to careful about DESTROY. Such complexity is uncalled for in most cases, and certainly in this one. =end original &AUTOLOADメソッドを用いる解決法も、うまくはいきますが、このアプローチを 満足の行くものであると立証するのは、見込がありません。 関数はクラス属性とオブジェクト属性の間を区別しなければなりません。 継承に干渉します。 また、DESTORY に注意する必要があります。 このような複雑性は、ほとんどの場合でお呼びではありません。 もちろん、この場合も。 =begin original You may wonder why we're rescinding strict refs for the loop. We're manipulating the package's symbol table to introduce new function names using symbolic references (indirect naming), which the strict pragma would otherwise forbid. Normally, symbolic references are a dodgy notion at best. This isn't just because they can be used accidentally when you aren't meaning to. It's also because for most uses to which beginning Perl programmers attempt to put symbolic references, we have much better approaches, like nested hashes or hashes of arrays. But there's nothing wrong with using symbolic references to manipulate something that is meaningful only from the perspective of the package symbol table, like method names or package variables. In other words, when you want to refer to the symbol table, use symbol references. =end original なぜ、strict refs をループで無効にしているのだろうと思うかも知れません。 パッケージのシンボルテーブルを操作して、新しい関数名をシンボリック リファレンスを使って(間接的な命名で)導入しています。 シンボリックリファレンスは、strict プラグマが禁じているものです。 ふつうは、シンボリックリファレンスは、せいぜい危なっかしい考えです。 ただ、意図しないときに、あやまって使われる可能性があるので、危なっかしいと いうだけです。 初心者の Perl プログラマがシンボリックリファレンスを置こうとする、 使いかたのほとんどには、ネストされたハッシュや配列のハッシュのような、 より良いアプローチがあるからです。 ですが、メソッド名やパッケージ変数のようなパッケージのシンボルテーブルの 観点からのみ、意味があることを操作するのに、シンボリックリファレンスを 使うのは、何も間違っていません。 言い替えれば、シンボルテーブルを参照したい場合は、シンボリックリファレンスを 使ってください。 =begin original Clustering all the class attributes in one place has several advantages. They're easy to spot, initialize, and change. The aggregation also makes them convenient to access externally, such as from a debugger or a persistence package. The only possible problem is that we don't automatically know the name of each class's class object, should it have one. This issue is addressed below in L<"The Eponymous Meta-Object">. =end original 一つの場所に、全てのクラス属性を集積するのは、さまざまな利点があります。 クラス属性は、目に付きやすく、初期化しやすく、変更しやすい。 集約することで、クラス属性を外部から、例えば、デバッガや永続的な パッケージから、アクセスするのが便利になります。 唯一ありそうな問題は、それぞれのクラスが持っているはずの クラスオブジェクトの名前を自動的には知らないことです。 この問題は、下の方の L<"The Eponymous Meta-Object"> に、扱われています。 =head2 Inheritance Concerns (継承の懸念) =begin original Suppose you have an instance of a derived class, and you access class data using an inherited method call. Should that end up referring to the base class's attributes, or to those in the derived class? How would it work in the earlier examples? The derived class inherits all the base class's methods, including those that access class attributes. But what package are the class attributes stored in? =end original 派生クラスのインスタンスがあったとして、継承されたメソッド呼び出しを使い、 クラスデータにアクセスします。 このとき、結局、基底クラスの属性を参照することになるべきなのか、 派生クラスの属性を参照することになるべきでしょうか? さっきの例ではどのように動くでしょうか? 派生クラスは基底クラスの全てのメソッドを継承します。 クラス属性にアクセスするメソッドも含みます。 ですが、どのパッケージにクラス属性が格納されるのでしょうか? =begin original The answer is that, as written, class attributes are stored in the package into which those methods were compiled. When you invoke the &CData1 method on the name of the derived class or on one of that class's objects, the version shown above is still run, so you'll access $Some_Class::CData1--or in the method cloning version, C<$Some_Class::ClassData{CData1}>. =end original 答えは、書かれたように、クラス属性はそれらのメソッドがコンパイルされた パッケージに、格納されます。 &CData1 メソッドを、派生クラスの名前か、派生クラスのオブジェクトで呼び出すと、 上で示されたバージョンのものが動きます。 つまり、$Some_Class::Cdata1 -- または、クローニングしているバージョンの メソッドで、C<$Some_Class::ClassData{CData1}>に、アクセスできます。 =begin original Think of these class methods as executing in the context of their base class, not in that of their derived class. Sometimes this is exactly what you want. If Feline subclasses Carnivore, then the population of Carnivores in the world should go up when a new Feline is born. But what if you wanted to figure out how many Felines you have apart from Carnivores? The current approach doesn't support that. =end original 派生クラスのコンテキストではなく、 基底クラスのコンテキストで実行するようなクラスメソッドを考えましょう。 お望みのものにびったりなことがあります。 猫は肉食動物の下位に分類されれば、新たに猫が生まれると、世界の肉食動物の 固体数が増えます。 ですが、肉食動物とは切り離して、何匹の猫がいるかを数えたいなら どうしましょう? 現在のアプローチではそれには対応できません。 =begin original You'll have to decide on a case-by-case basis whether it makes any sense for class attributes to be package-relative. If you want it to be so, then stop ignoring the first argument to the function. Either it will be a package name if the method was invoked directly on a class name, or else it will be an object reference if the method was invoked on an object reference. In the latter case, the ref() function provides the class of that object. =end original クラス属性が package-relative であることに筋が通っているかどうかを、 ケースバイケースの根拠で決める必要があるでしょう。 package-relative でありたいなら、関数の第一引数を無視するのをやめます。 第一引数は、メソッドがクラス名で直接に呼ばれたなら、パッケージ名、 オブジェクトリファレンスで呼ばれたなら、オブジェクトリファレンスの、 どちらかです。 後者では、ref() 関数がオブジェクトのクラス名を与えます。 package Some_Class; sub CData1 { my $obclass = shift; my $class = ref($obclass) || $obclass; my $varname = $class . "::CData1"; no strict "refs"; # to access package data symbolically $$varname = shift if @_; return $$varname; } =begin original And then do likewise for all other class attributes (such as CData2, etc.) that you wish to access as package variables in the invoking package instead of the compiling package as we had previously. =end original 以前にしたようなコンパイルしているパッケージではなく、呼び出している パッケージのパッケージ変数としてアクセスしたいと思っている、 他の全てのクラス属性(CData2 などのように)と同じようにしたいでしょう。 =begin original Once again we temporarily disable the strict references ban, because otherwise we couldn't use the fully-qualified symbolic name for the package global. This is perfectly reasonable: since all package variables by definition live in a package, there's nothing wrong with accessing them via that package's symbol table. That's what it's there for (well, somewhat). =end original ここで、再び、一時的に strict references を禁止するのをやめましょう。 そうしないと、パッケージのグローバル変数のために、完全に適格なシンボル名を 使うことが出来ないからです。 このことは、完全に合理的です:全てのパッケージ変数は、定義により、 パッケージに生きています。 パッケージのシンボル名経由で、パッケージ変数に アクセスするのは何も間違っていません。 そのためにそれがあるのです(たぶん)。 =begin original What about just using a single hash for everything and then cloning methods? What would that look like? The only difference would be the closure used to produce new method entries for the class's symbol table. =end original 全てのもののために、ただ一つのハッシュを使い、メソッドを複製しては どうでしょうか? どのように見えるでしょう? 唯一の違いは、クラスのシンボルテーブルに新しいメソッドを生み出すのに、 クロージャが使われていることです。 no strict "refs"; *$datum = sub { my $obclass = shift; my $class = ref($obclass) || $obclass; my $varname = $class . "::ClassData"; $varname->{$datum} = shift if @_; return $varname->{$datum}; } =head2 The Eponymous Meta-Object (クラスの名前のメタオブジェクト) =begin original It could be argued that the %ClassData hash in the previous example is neither the most imaginative nor the most intuitive of names. Is there something else that might make more sense, be more useful, or both? =end original 前の例の、%ClassDataハッシュは、変数名が創意に富んでも、直観的でもないと、 主張されるかもしれません。 もっと意味があるか、有益なものか、その両方を備えたものはないでしょうか? =begin original As it happens, yes, there is. For the "class meta-object", we'll use a package variable of the same name as the package itself. Within the scope of a package Some_Class declaration, we'll use the eponymously named hash %Some_Class as that class's meta-object. (Using an eponymously named hash is somewhat reminiscent of classes that name their constructors eponymously in the Python or C++ fashion. That is, class Some_Class would use &Some_Class::Some_Class as a constructor, probably even exporting that name as well. The StrNum class in Recipe 13.14 in I does this, if you're looking for an example.) =end original はい、ちょうどよくあります。 "クラスのメタオブジェクト"に、パッケージと同じ名前のパッケージ変数を 使いましょう。 Some_Class のパッケージ宣言のスコープ内で、クラスのメタオブジェクトとして、 %Some_Class という、クラスの名前のハッシュを使いましょう。 (クラスの名前のハッシュは、コンストラクタをクラスの名前にする、 Python や、C++ 流儀のクラスをちょっと思い出させます。 つまり、Some_Class クラスが &Some_Class::Some_Class をコンストラクタと するということです。 おそらく、その名前を同様にエクスポートさえしているでしょう。 例をお探しなら、I の StrNum クラスは、そのように しています)。 =begin original This predictable approach has many benefits, including having a well-known identifier to aid in debugging, transparent persistence, or checkpointing. It's also the obvious name for monadic classes and translucent attributes, discussed later. =end original このありきたりなアプローチには、多くの利益があります。 よくわかる一意の名前を含むことで、デバッグや透過的な永続生やチェックポイントの 助けになります。 後で述べる、一価のクラスと半透明な属性にとっても、明らかな名前です。 =begin original Here's an example of such a class. Notice how the name of the hash storing the meta-object is the same as the name of the package used to implement the class. =end original 下のものは、そのようなクラスの例です。 メタオブジェクトを格納しているハッシュの名前が、どのようにして、 クラスを実装するのに使われているパッケージの名前と同じに しているかに気を付けてください。 package Some_Class; use strict; =begin original # create class meta-object using that most perfect of names our %Some_Class = ( # our() is new to perl5.6 CData1 => "", CData2 => "", ); =end original # 完全な名前を使ってクラスのメタオブジェクトを作る our %Some_Class = ( # our() is new to perl5.6 CData1 => "", CData2 => "", ); =begin original # this accessor is calling-package-relative sub CData1 { my $obclass = shift; my $class = ref($obclass) || $obclass; no strict "refs"; # to access eponymous meta-object $class->{CData1} = shift if @_; return $class->{CData1}; } =end original # このアクセサはcalling-package-relative sub CData1 { my $obclass = shift; my $class = ref($obclass) || $obclass; no strict "refs"; # to access eponymous meta-object $class->{CData1} = shift if @_; return $class->{CData1}; } =begin original # but this accessor is not sub CData2 { shift; # XXX: ignore calling class/object no strict "refs"; # to access eponymous meta-object __PACKAGE__ -> {CData2} = shift if @_; return __PACKAGE__ -> {CData2}; } =end original # こちらのアクセサは違います sub CData2 { shift; # XXX: ignore calling class/object no strict "refs"; # to access eponymous meta-object __PACKAGE__ -> {CData2} = shift if @_; return __PACKAGE__ -> {CData2}; } =begin original In the second accessor method, the __PACKAGE__ notation was used for two reasons. First, to avoid hardcoding the literal package name in the code in case we later want to change that name. Second, to clarify to the reader that what matters here is the package currently being compiled into, not the package of the invoking object or class. If the long sequence of non-alphabetic characters bothers you, you can always put the __PACKAGE__ in a variable first. =end original 2 番目のアクセサで、__PACKAGE__ 記法が、2つの理由から使われています。 1 つ目の理由は、後で、名前を変えたくなった際に、コードにパッケージの名前を リテラルでハードコーディングするのは避けたいからです。 2 つ目の理由は、コードを読む人に、ここで何が問題なのかをはっきり させるためです。 ここでの問題は、現在コンパイルされているパッケージであり、 オブジェクトかクラスを呼び出したパッケージではないということです。 アルファベットでない文字列が長く続くのが面倒なら、 常に、変数の最初に、__PACKAGE__ を置いてください。 =begin original sub CData2 { shift; # XXX: ignore calling class/object no strict "refs"; # to access eponymous meta-object my $class = __PACKAGE__; $class->{CData2} = shift if @_; return $class->{CData2}; } =end original sub CData2 { shift; # XXX: クラス/オブジェクトの呼び出しを無視し、 no strict "refs"; # クラスの名前のメタオブジェクトにアクセスします。 my $class = __PACKAGE__; $class->{CData2} = shift if @_; return $class->{CData2}; } =begin original Even though we're using symbolic references for good not evil, some folks tend to become unnerved when they see so many places with strict ref checking disabled. Given a symbolic reference, you can always produce a real reference (the reverse is not true, though). So we'll create a subroutine that does this conversion for us. If invoked as a function of no arguments, it returns a reference to the compiling class's eponymous hash. Invoked as a class method, it returns a reference to the eponymous hash of its caller. And when invoked as an object method, this function returns a reference to the eponymous hash for whatever class the object belongs to. =end original ずっとシンボリックリファレンスを使っていますが、悪くはありません。 ずいぶん多くの場所で、strict ref のチェックを無効にしているのに、 うろたえがちな人がいるでしょうけど。 シンボリックリファレンスであれば、常に、本当のリファレンスを作れます (その逆は真ではありませんが)。 このシンボリックリファレンスから本当のリファレンスへの変換をする サブルーチンを作りましょう。 引数無しで呼ばれたら、コンパイルしているクラスの名前のハッシュへの リファレンスを返します。 クラスメソッドとして呼ばれたら、その呼び出したクラスの名前のハッシュへの リファレンスを返します。 オブジェクトメソッドとして呼ばれたら、この関数は、オブジェクトが 属している、どんなクラスでも、クラスの名前のハッシュへの リファレンスを返します。 package Some_Class; use strict; our %Some_Class = ( # our() is new to perl5.6 CData1 => "", CData2 => "", ); =begin original # tri-natured: function, class method, or object method sub _classobj { my $obclass = shift || __PACKAGE__; my $class = ref($obclass) || $obclass; no strict "refs"; # to convert sym ref to real one return \%$class; } =end original # tri-natured: function, class method, or object method sub _classobj { my $obclass = shift || __PACKAGE__; my $class = ref($obclass) || $obclass; no strict "refs"; # シンボリックリファレンスを本当のリファレンスへと変換する return \%$class; } =begin original for my $datum (keys %{ _classobj() } ) { # turn off strict refs so that we can # register a method in the symbol table no strict "refs"; *$datum = sub { use strict "refs"; my $self = shift->_classobj(); $self->{$datum} = shift if @_; return $self->{$datum}; } } =end original for my $datum (keys %{ _classobj() } ) { # strict refs をオフにするので、 # シンボルテーブルにメソッドを登録できます。 no strict "refs"; *$datum = sub { use strict "refs"; my $self = shift->_classobj(); $self->{$datum} = shift if @_; return $self->{$datum}; } } =head2 Indirect References to Class Data (間接的なクラスデータへのリファレンス) =begin original A reasonably common strategy for handling class attributes is to store a reference to each package variable on the object itself. This is a strategy you've probably seen before, such as in L and L, but there may be variations in the example below that you haven't thought of before. =end original クラス属性を取り扱うの合理的で一般的な作戦とは、 オブジェクトそれ自身で、それぞれのパッケージ変数へのリファレンスを 格納することです。 これは、おそらく既にみた作戦です。 L や、L にあるようなものです。 ですが、まだ考えたことのないようなバリエーションの例が下にあります。 package Some_Class; our($CData1, $CData2); # our() is new to perl5.6 sub new { my $obclass = shift; return bless my $self = { ObData1 => "", ObData2 => "", CData1 => \$CData1, CData2 => \$CData2, } => (ref $obclass || $obclass); } sub ObData1 { my $self = shift; $self->{ObData1} = shift if @_; return $self->{ObData1}; } sub ObData2 { my $self = shift; $self->{ObData2} = shift if @_; return $self->{ObData2}; } sub CData1 { my $self = shift; my $dataref = ref $self ? $self->{CData1} : \$CData1; $$dataref = shift if @_; return $$dataref; } sub CData2 { my $self = shift; my $dataref = ref $self ? $self->{CData2} : \$CData2; $$dataref = shift if @_; return $$dataref; } =begin original As written above, a derived class will inherit these methods, which will consequently access package variables in the base class's package. This is not necessarily expected behavior in all circumstances. Here's an example that uses a variable meta-object, taking care to access the proper package's data. =end original 上に書いたように、派生クラスが、これらのメソッドを継承します。 これらのメソッドは基底クラスのパッケージのパッケージ変数に持続的に アクセスします。 このことは、全ての状況で、必要とされ、期待された振る舞いではありません。 変数、メタオブジェクトを使う例があります。 適当なパッケージのデータへのアクセスを解決します。 package Some_Class; use strict; our %Some_Class = ( # our() is new to perl5.6 CData1 => "", CData2 => "", ); sub _classobj { my $self = shift; my $class = ref($self) || $self; no strict "refs"; # get (hard) ref to eponymous meta-object return \%$class; } sub new { my $obclass = shift; my $classobj = $obclass->_classobj(); bless my $self = { ObData1 => "", ObData2 => "", CData1 => \$classobj->{CData1}, CData2 => \$classobj->{CData2}, } => (ref $obclass || $obclass); return $self; } sub ObData1 { my $self = shift; $self->{ObData1} = shift if @_; return $self->{ObData1}; } sub ObData2 { my $self = shift; $self->{ObData2} = shift if @_; return $self->{ObData2}; } sub CData1 { my $self = shift; $self = $self->_classobj() unless ref $self; my $dataref = $self->{CData1}; $$dataref = shift if @_; return $$dataref; } sub CData2 { my $self = shift; $self = $self->_classobj() unless ref $self; my $dataref = $self->{CData2}; $$dataref = shift if @_; return $$dataref; } =begin original Not only are we now strict refs clean, using an eponymous meta-object seems to make the code cleaner. Unlike the previous version, this one does something interesting in the face of inheritance: it accesses the class meta-object in the invoking class instead of the one into which the method was initially compiled. =end original 今、strict ref を取り除いているだけでなく、クラスの名前のメタオブジェクトを 使って、コードクリーナーを作っているようです。 前のバージョンとは違い、これは、継承に直面すると、ちょっと面白いことを します: これは、呼び出しているクラスの、クラスのメタオブジェクトにアクセスします。 メソッドが最初にコンパイルされたクラスではありません。 =begin original You can easily access data in the class meta-object, making it easy to dump the complete class state using an external mechanism such as when debugging or implementing a persistent class. This works because the class meta-object is a package variable, has a well-known name, and clusters all its data together. (Transparent persistence is not always feasible, but it's certainly an appealing idea.) =end original クラスのメタオブジェクトのデータに簡単にアクセスすることが出来ます。 デバッギングや、永続クラスを実装するときのような外部のメカニズムを使って、 完全なクラスの状態を簡単にダンプできます。 このように働くのは、クラスのメタオブジェクトがパッケージ変数であり、 よく知られた名前を持ち、全てのそのデータを一緒にまとめているからです。 (透過的な永続生は常に適しているわけではありませんが、魅力的なアイデアで あるのは確かです。) =begin original There's still no check that object accessor methods have not been invoked on a class name. If strict ref checking is enabled, you'd blow up. If not, then you get the eponymous meta-object. What you do with--or about--this is up to you. The next two sections demonstrate innovative uses for this powerful feature. =end original まだ、オブジェクトのアクセサメソッドがクラスの名前で呼び出されていないことを チェックしていません。 strict ref のチェックが有効なら、壊れます。 そうでなければ、クラスの名前のメタオブジェクトを得ます。 それを我慢するか、なんとかするかは、あなた次第です。 次の 2 つのセクションで、この強力な特徴の画期的な利用法を、 デモンストレーションします。 =head2 Monadic Classes (一価のクラス) =begin original Some of the standard modules shipped with Perl provide class interfaces without any attribute methods whatsoever. The most commonly used module not numbered amongst the pragmata, the Exporter module, is a class with neither constructors nor attributes. Its job is simply to provide a standard interface for modules wishing to export part of their namespace into that of their caller. Modules use the Exporter's &import method by setting their inheritance list in their package's @ISA array to mention "Exporter". But class Exporter provides no constructor, so you can't have several instances of the class. In fact, you can't have any--it just doesn't make any sense. All you get is its methods. Its interface contains no statefulness, so state data is wholly superfluous. =end original Perlに載っている標準モジュールには、何の属性メソッドも一切ない、 クラスインターフェースを提供しているものがいくつかあります。 もっとも普通に使われているモジュールは、プラグマを数にいれなければ、 Exporter モジュールです。 このモジュールは、コンストラクタも、属性もないクラスです。 Exporter の仕事は、単純に、モジュールが呼び出しもとに自分の名前空間の一部を エクスポートする、 標準のインターフェースを提供することです。 モジュールは 、それぞれのモジュールの@ISA配列に継承のリストをセットすることで、 Exporter の &import メソッドを使い、"Exporter" に記載します。 ですが、クラスの Exporter には、コンストラクタがありません。 そのため、複数のクラスのインスタンスを持つことが出来ません。 実際に、一つももてません -- 全く意味をなさない。 あなたが得る全てのものは、そのメソッドです、 そのインターフェースには、なんの状態も含みません。 ですので、状態のデータはまったく不要なのです。 =begin original Another sort of class that pops up from time to time is one that supports a unique instance. Such classes are called I, or less formally, I or I. =end original 別の種類のクラスで、時間から時間までを取得するモジュールは、 単一のインスタンスをサポートするものです。 このようなクラスは I<一価のクラス> と呼ばれます。 または、あまり正式ではありませんが、I とか、 Iと 呼ばれます。 =begin original If a class is monadic, where do you store its state, that is, its attributes? How do you make sure that there's never more than one instance? While you could merely use a slew of package variables, it's a lot cleaner to use the eponymously named hash. Here's a complete example of a monadic class: =end original クラスが一価であれば、その状態、すなわち、属性をどこに格納するのでしょう。 一つのインスタンスより他にはないと、どのように確認するでしょうか? たくさんのパッケージ変数を単に使うこともできますが、 クラスの名前のハッシュを使うクリーナーを使うことも非常にあります。 一価のクラスの完全な例です: package Cosmos; %Cosmos = (); =begin original # accessor method for "name" attribute sub name { my $self = shift; $self->{name} = shift if @_; return $self->{name}; } =end original # "name" 属性のアクセサメソッド sub name { my $self = shift; $self->{name} = shift if @_; return $self->{name}; } =begin original # read-only accessor method for "birthday" attribute sub birthday { my $self = shift; die "can't reset birthday" if @_; # XXX: croak() is better return $self->{birthday}; } =end original # "birthday" 属性の読み込みのみのアクセサメソッド sub birthday { my $self = shift; die "can't reset birthday" if @_; # XXX: croak() is better return $self->{birthday}; } =begin original # accessor method for "stars" attribute sub stars { my $self = shift; $self->{stars} = shift if @_; return $self->{stars}; } =end original # "stars" 属性のアクセサメソッド sub stars { my $self = shift; $self->{stars} = shift if @_; return $self->{stars}; } =begin original # oh my - one of our stars just went out! sub supernova { my $self = shift; my $count = $self->stars(); $self->stars($count - 1) if $count > 0; } =end original # おや、まあ! - 星が一つ、死んでしまった! sub supernova { my $self = shift; my $count = $self->stars(); $self->stars($count - 1) if $count > 0; } =begin original # constructor/initializer method - fix by reboot sub bigbang { my $self = shift; %$self = ( name => "the world according to tchrist", birthday => time(), stars => 0, ); return $self; # yes, it's probably a class. SURPRISE! } =end original # コンストラクタ/イニシャライザ - リブートで直される sub bigbang { my $self = shift; %$self = ( name => "the world according to tchrist", birthday => time(), stars => 0, ); return $self; # はい、おそらくクラスです。 びっくり! } =begin original # After the class is compiled, but before any use or require # returns, we start off the universe with a bang. __PACKAGE__ -> bigbang(); =end original # クラスがコンパイルされた後、ですが、use も require も戻る前、 # バンとともに、宇宙が動き始めます。 __PACKAGE__ -> bigbang(); =begin original Hold on, that doesn't look like anything special. Those attribute accessors look no different than they would if this were a regular class instead of a monadic one. The crux of the matter is there's nothing that says that $self must hold a reference to a blessed object. It merely has to be something you can invoke methods on. Here the package name itself, Cosmos, works as an object. Look at the &supernova method. Is that a class method or an object method? The answer is that static analysis cannot reveal the answer. Perl doesn't care, and neither should you. In the three attribute methods, C<%$self> is really accessing the %Cosmos package variable. =end original そのままでいてください。 何も特別なようにはみえません。 これらの属性アクセサは一価のクラスであるか、普通のクラスであるかで、 することは何も違いません。 ここでの最重要ポイントは $self がオブジェクトに bless されたリファレンスを 持たなければならないとは言わないところです。 単に、メソッドを呼ぶことができれば、何でもいいのです。 パッケージの名前自身、Cosmos でも、オブジェクトのように働きます。 &supernova メソッドをみてください。 これは、クラスメソッドか、オブジェクトメソッドでしょうか? その答えは、静的な解析ではその答えを知らせることはできないということです。 Perlは、気にしませんし、あなたも気にしないべきです。 3 つの属性メソッドで、C<%$self> は、実際は、%Cosmos パッケージ変数に アクセスしています。 =begin original If like Stephen Hawking, you posit the existence of multiple, sequential, and unrelated universes, then you can invoke the &bigbang method yourself at any time to start everything all over again. You might think of &bigbang as more of an initializer than a constructor, since the function doesn't allocate new memory; it only initializes what's already there. But like any other constructor, it does return a scalar value to use for later method invocations. =end original ステファン・ホーキングのように、複数の、連続の、関係のない宇宙の存在を 仮定するなら、 &bigbang メソッドを自分で呼び、いつでも、そっくり再び、全てを 始めることができます。 &bigbang を、コンストラクタよりも、もっとイニシャライザとして、 考えているかもしれません。 &bigbang は、新たのメモリを割り当てません、すなわち、&bingbang は、既に そこにあるものを、初期化するだけというために。 ですが、他のどんなコンストラクタと同じように、後のメソッド呼び出しに 使うために、スカラ値をを返します。 =begin original Imagine that some day in the future, you decide that one universe just isn't enough. You could write a new class from scratch, but you already have an existing class that does what you want--except that it's monadic, and you want more than just one cosmos. =end original 将来のいつかに、一つの宇宙では十分ではないと、決心したとしましょう。 スクラッチから新しいクラスを書くこともできますが、 既存のクラスがあります -- 一価であることを除いて、望むクラスがあり、 しかも、ただ、2 つ以上の宇宙が欲しいだけです。 =begin original That's what code reuse via subclassing is all about. Look how short the new code is: =end original サブクラスでコードの再利用することが全てです。 新しいコードがどのくらい短いか、見てみましょう。 package Multiverse; use Cosmos; @ISA = qw(Cosmos); sub new { my $protoverse = shift; my $class = ref($protoverse) || $protoverse; my $self = {}; return bless($self, $class)->bigbang(); } 1; =begin original Because we were careful to be good little creators when we designed our Cosmos class, we can now reuse it without touching a single line of code when it comes time to write our Multiverse class. The same code that worked when invoked as a class method continues to work perfectly well when invoked against separate instances of a derived class. =end original Cosmosクラスを設計している時に、慎重であり、良い小さなクリエータであったので、 Multiverse クラスを書く際に、コードの一行もいじらないで、Cosmos クラスを 再利用することができます。 クラスメソッドとして呼ばれたときに動く同じコードが派生クラスの個々の インスタンスから呼ばれても、完全に、うまく、動き続けます。 =begin original The astonishing thing about the Cosmos class above is that the value returned by the &bigbang "constructor" is not a reference to a blessed object at all. It's just the class's own name. A class name is, for virtually all intents and purposes, a perfectly acceptable object. It has state, behavior, and identity, the three crucial components of an object system. It even manifests inheritance, polymorphism, and encapsulation. And what more can you ask of an object? =end original 上にあげた、Cosmos クラスでびっくりするのは、&bigbang "コンストラクタ" が 返す値が、まったく、bless されたオブジェクトへのリファレンスではないことです。 &bigbang コンストラクタが返す値は、クラス自身の名前です。 クラス名は、全ての目的と手段にとって、実質的に、完全に条件を満たしている オブジェクトです。 状態、振舞、同一性、3つの、オブジェクトシステムの重大な構成要素が、 クラス名にはあります。 クラス名は、継承、ポリモルフィズム、カプセル化さえも明らかにします。 オブジェクトにこれ以上何を要求できますか? =begin original To understand object orientation in Perl, it's important to recognize the unification of what other programming languages might think of as class methods and object methods into just plain methods. "Class methods" and "object methods" are distinct only in the compartmentalizing mind of the Perl programmer, not in the Perl language itself. =end original Perl でオブジェクト指向を理解するために、他のプログラミング言語が クラスメソッドとオブジェクトメソッドについて考えていることを、ただの単純な メソッドに統一することを認識するのが重要です。 "クラスメソッド"と、"オブジェクトメソッド"は、Perl プログラマが心の中で 区切っているだけで、Perl 言語それ自身の中では、区切られていません。 =begin original Along those same lines, a constructor is nothing special either, which is one reason why Perl has no pre-ordained name for them. "Constructor" is just an informal term loosely used to describe a method that returns a scalar value that you can make further method calls against. So long as it's either a class name or an object reference, that's good enough. It doesn't even have to be a reference to a brand new object. =end original これらの同じ行の間で、コンストラクタは、何も特別なものではありません。 Perlには、それらの行に、神によって定められている名前はないのがその理由です。 "コンストラクタ"は公式ではない述語であり、後でメソッドを呼ぶことのできる スカラー値を返すメソッドを説明するのを使います。 クラス名もオブジェクトリファレンスでありさえすれば、十分、上等です。 おろしたてのオブジェクトがリファレンスである必要さえないのです。 =begin original You can have as many--or as few--constructors as you want, and you can name them whatever you care to. Blindly and obediently using new() for each and every constructor you ever write is to speak Perl with such a severe C++ accent that you do a disservice to both languages. There's no reason to insist that each class have but one constructor, or that a constructor be named new(), or that a constructor be used solely as a class method and not an object method. =end original 自分が望むのと同じくらい、多くの -- または、ほとんどない -- 、コンストラクタを 持つことができますし、自分がしたいように何でも名前を付けることができます。 やみくもに、素直に、いままで書いた、ありとあらゆるコンストラクタに、 new() を使うことは、両方の言語にひどい仕打をする、厳格な C++ の アクセントのようなもので、Perl を喋ることです。 それぞれのクラスに一つのコンストラクタがあるとか、または、コンストラクタは new() と名付けられるとか、コンストラクタはオブジェクトメソッドではなく、 ただクラスメソッドとして使われるとか、そういうことを強く主張する理由は まったくありません。 =begin original The next section shows how useful it can be to further distance ourselves from any formal distinction between class method calls and object method calls, both in constructors and in accessor methods. =end original 次のセクションでは、コンストラクタとアクセサメソッドの両方で、 クラスメソッドとオブジェクトメソッドの呼び出しとの間で、 正式な区別から、我々自身がさらに遠くまでありうるということが、 どれくらい有益であるかを示します。 =head2 Translucent Attributes (半透明の属性) =begin original A package's eponymous hash can be used for more than just containing per-class, global state data. It can also serve as a sort of template containing default settings for object attributes. These default settings can then be used in constructors for initialization of a particular object. The class's eponymous hash can also be used to implement I. A translucent attribute is one that has a class-wide default. Each object can set its own value for the attribute, in which case C<< $object->attribute() >> returns that value. But if no value has been set, then C<< $object->attribute() >> returns the class-wide default. =end original パッケージの名前のハッシュは、単にクラス単位のグローバルな状態のデータを 持つこと以上のことに使えます。 オブジェクト属性のデフォルトの設定を持つ、一種のテンプレートとしての役目も 出来ます。 これらのデフォルトの設定は、コンストラクタで、特定のオブジェクトの初期化の ために使うことができます。 クラスの名前のハッシュは、I<半透明の属性> を実装するのにも使えます。 半透明の属性とは、クラスワイドのデフォルトを持つ属性です。 それぞれのオブジェクトは属性にそれ自身の値をセットできます、 そこでは、C<< $object->attribute() >> で、値を返します。 ですが、値がまだセットされていなければ、C<< $object->attribute() >> は、 クラスワイドのデフォルトを返します。 =begin original We'll apply something of a copy-on-write approach to these translucent attributes. If you're just fetching values from them, you get translucency. But if you store a new value to them, that new value is set on the current object. On the other hand, if you use the class as an object and store the attribute value directly on the class, then the meta-object's value changes, and later fetch operations on objects with uninitialized values for those attributes will retrieve the meta-object's new values. Objects with their own initialized values, however, won't see any change. =end original これらの半透明の属性に、コピー・オン・ライトのアプローチの何かを 適用するでしょう。 これらの属性からただ、値を取りだしているならば、半透明性を得ます。 ですが、これらの属性に新しい値を蓄えるなら、新しい値は現在のオブジェクトに セットされます。 一方、クラスをオブジェクトとして使い、直接にクラスで属性値を蓄えるなら、 メタオブジェクトの値が変更され、その後で、それらの属性の値が 初期化されていないオブジェクトで取り出し操作を行うと、 メタオブジェクトの新しい値を取り出すことになります。 しかし、オブジェクトが自身の初期化値を持つ場合は、変更は見えません。 =begin original Let's look at some concrete examples of using these properties before we show how to implement them. Suppose that a class named Some_Class had a translucent data attribute called "color". First you set the color in the meta-object, then you create three objects using a constructor that happens to be named &spawn. =end original どのように実装するかを見せる前に、これらのプロパティを使う、具体的な例を 見てみましょう。 Some_Class という名前のクラスに、"color" という半透明のクラス属性が あるとします。 まず、meta-object のカラーをセットします。 それから、コンストラクタを使って、3つ のオブジェクトをつくります。 コンストラクタは、たまたま &spawn という名前です。 use Vermin; Vermin->color("vermilion"); $ob1 = Vermin->spawn(); # so that's where Jedi come from $ob2 = Vermin->spawn(); $ob3 = Vermin->spawn(); print $obj3->color(); # prints "vermilion" =begin original Each of these objects' colors is now "vermilion", because that's the meta-object's value for that attribute, and these objects do not have individual color values set. =end original それぞれのオブジェクトの色は、現在、"vermilion(朱色)" です。 メタオブジェクトのその属性の値がそれであり、それぞれのオブジェクトに個別の 色の値がセットされていないからです。 =begin original Changing the attribute on one object has no effect on other objects previously created. =end original あるオブジェクトの属性を変更しても、先に作られた他のオブジェクトの値には 影響しません。 $ob3->color("chartreuse"); print $ob3->color(); # prints "chartreuse" print $ob1->color(); # prints "vermilion", translucently =begin original If you now use $ob3 to spawn off another object, the new object will take the color its parent held, which now happens to be "chartreuse". That's because the constructor uses the invoking object as its template for initializing attributes. When that invoking object is the class name, the object used as a template is the eponymous meta-object. When the invoking object is a reference to an instantiated object, the &spawn constructor uses that existing object as a template. =end original $ob3 を使い、他のオブジェクトを産んでみると、新しいオブジェクトは、 その親が持っている色を取るでしょう。 今は、たまたま、"chartreuse(淡黄緑色)" になるでしょう。 コンストラクタが、初期化の属性のテンプレートとして、呼び出したオブジェクトを 使うからです。 呼び出すオブジェクトがクラス名であれば、オブジェクトは、クラスの メタオブジェクトを参照します。 呼び出すオブジェクトが説明されたオブジェクトへのリファレンスであれば、 &spawn コンストラクタは、テンプレートとして、存在するオブジェクトを使います。 $ob4 = $ob3->spawn(); # $ob3 now template, not %Vermin print $ob4->color(); # prints "chartreuse" =begin original Any actual values set on the template object will be copied to the new object. But attributes undefined in the template object, being translucent, will remain undefined and consequently translucent in the new one as well. =end original テンプレートオブジェクトにセットされる実際の値は、どんなものも、 新しいオブジェクトにコピーされます。 ですが、テンプレートオブジェクトに未定義の属性は、半透明になり、未定義の ままとなり、その結果、新しいものも同様に半透明です。 =begin original Now let's change the color attribute on the entire class: =end original 今度は、クラス全体のcolor属性を変更しましょう: Vermin->color("azure"); print $ob1->color(); # prints "azure" print $ob2->color(); # prints "azure" print $ob3->color(); # prints "chartreuse" print $ob4->color(); # prints "chartreuse" =begin original That color change took effect only in the first pair of objects, which were still translucently accessing the meta-object's values. The second pair had per-object initialized colors, and so didn't change. =end original この色の変更はオブジェクトの最初の2つにのみ、影響します。 この 2 つは、まだ、半透明で、メタオブジェクトの値にアクセスします。 後の 2 つは、オブジェクトごとに、初期化された色がありました。 そのため、変更されません。 =begin original One important question remains. Changes to the meta-object are reflected in translucent attributes in the entire class, but what about changes to discrete objects? If you change the color of $ob3, does the value of $ob4 see that change? Or vice-versa. If you change the color of $ob4, does then the value of $ob3 shift? =end original 一つ、重要な疑問があります。 メタオブジェクトの値を変えることは、クラス全体の半透明の属性に反映されます。 ですが、オブジェクトを絶やす変更はどうでしょうか? $ob3 の色を変更したら、$ob4 にはその変更がわかるでしょうか? また、逆の場合も同じく。 もし、$ob4 の色を変更したら、$ob4 の値は変わるでしょうか? $ob3->color("amethyst"); print $ob3->color(); # prints "amethyst" print $ob4->color(); # hmm: "chartreuse" or "amethyst"? =begin original While one could argue that in certain rare cases it should, let's not do that. Good taste aside, we want the answer to the question posed in the comment above to be "chartreuse", not "amethyst". So we'll treat these attributes similar to the way process attributes like environment variables, user and group IDs, or the current working directory are treated across a fork(). You can change only yourself, but you will see those changes reflected in your unspawned children. Changes to one object will propagate neither up to the parent nor down to any existing child objects. Those objects made later, however, will see the changes. =end original まれなケースでは、そうすべきであるという議論もありますが、 そうしないでおきましょう。 良識の問題は置いておいて、上記のコメントで提示されている質問で "amethyst" ではなく "chartreuse" になる答えが必要です。 環境変数、ユーザ ID やグループ ID や、fork() を超えて扱われるカレント ワーキングディレクトリといったプロセス属性処理するのと似たような方法で、 それらの属性を扱いましょう。 自分自身のみ変更できますが、これらの変更が、自身が作ったのではない 子に反映されることになります。 一つのオブジェクトの変更は、親オブジェクトや、存在する子オブジェクトには 伝播しません。 しかし、後で作られたこれらのオブジェクトは、変更がわかります。 =begin original If you have an object with an actual attribute value, and you want to make that object's attribute value translucent again, what do you do? Let's design the class so that when you invoke an accessor method with C as its argument, that attribute returns to translucency. =end original 実際の属性値でオブジェクトを持ち、オブジェクトの属性値を再び半透明に したければ、どうしましょうか? その引数に C を指定してアクセサメソッドを呼ぶとき、 その属性が再び半透明性になるようにクラスを設計しましょう。 $ob4->color(undef); # back to "azure" =begin original Here's a complete implementation of Vermin as described above. =end original 上で説明した Vermin の完全な実装です。 package Vermin; # here's the class meta-object, eponymously named. # it holds all class attributes, and also all instance attributes # so the latter can be used for both initialization # and translucency. our %Vermin = ( # our() is new to perl5.6 PopCount => 0, # capital for class attributes color => "beige", # small for instance attributes ); # constructor method # invoked as class method or object method sub spawn { my $obclass = shift; my $class = ref($obclass) || $obclass; my $self = {}; bless($self, $class); $class->{PopCount}++; # init fields from invoking object, or omit if # invoking object is the class to provide translucency %$self = %$obclass if ref $obclass; return $self; } # translucent accessor for "color" attribute # invoked as class method or object method sub color { my $self = shift; my $class = ref($self) || $self; # handle class invocation unless (ref $self) { $class->{color} = shift if @_; return $class->{color} } # handle object invocation $self->{color} = shift if @_; if (defined $self->{color}) { # not exists! return $self->{color}; } else { return $class->{color}; } } # accessor for "PopCount" class attribute # invoked as class method or object method # but uses object solely to locate meta-object sub population { my $obclass = shift; my $class = ref($obclass) || $obclass; return $class->{PopCount}; } # instance destructor # invoked only as object method sub DESTROY { my $self = shift; my $class = ref $self; $class->{PopCount}--; } =begin original Here are a couple of helper methods that might be convenient. They aren't accessor methods at all. They're used to detect accessibility of data attributes. The &is_translucent method determines whether a particular object attribute is coming from the meta-object. The &has_attribute method detects whether a class implements a particular property at all. It could also be used to distinguish undefined properties from non-existent ones. =end original 2、3 の便利になるヘルパーメソッドがあります。 これらは、まったく、アクセサメソッドではありません。 データ属性のアクセシビリティを見つけるのに使われています。 この &is_translucent メソッドは特別なオブジェクト属性が、 メタオブジェクトからくるのかどうかを決めています。 &has_attribute メソッドは、クラスが特別なプロパティを 少しでも実装しているかどうかを見つけます。 存在しないプロパティから、未定義のプロパティを区別するのにも、 使われ得ます。 # detect whether an object attribute is translucent # (typically?) invoked only as object method sub is_translucent { my($self, $attr) = @_; return !defined $self->{$attr}; } # test for presence of attribute in class # invoked as class method or object method sub has_attribute { my($self, $attr) = @_; my $class = ref($self) || $self; return exists $class->{$attr}; } =begin original If you prefer to install your accessors more generically, you can make use of the upper-case versus lower-case convention to register into the package appropriate methods cloned from generic closures. =end original より一般的に、アクセサをインストールしたいなら、 パッケージに、一般のクロージャからクローニングされた適切なメソッドを 登録するのに、大文字対小文字の慣習を利用することができます。 for my $datum (keys %{ +__PACKAGE__ }) { *$datum = ($datum =~ /^[A-Z]/) ? sub { # install class accessor my $obclass = shift; my $class = ref($obclass) || $obclass; return $class->{$datum}; } : sub { # install translucent accessor my $self = shift; my $class = ref($self) || $self; unless (ref $self) { $class->{$datum} = shift if @_; return $class->{$datum} } $self->{$datum} = shift if @_; return defined $self->{$datum} ? $self -> {$datum} : $class -> {$datum} } } =begin original Translations of this closure-based approach into C++, Java, and Python have been left as exercises for the reader. Be sure to send us mail as soon as you're done. =end original このクロージャベースのアプローチを、C++、Java、Python へ、 転換するのは、読者の課題として残しておきます。 できあがったらすぐに、きっと送ってくださいね。 =head1 Class Data as Lexical Variables (レキシカル変数のクラスデータ) =head2 Privacy and Responsibility (プライバシーと責任) =begin original Unlike conventions used by some Perl programmers, in the previous examples, we didn't prefix the package variables used for class attributes with an underscore, nor did we do so for the names of the hash keys used for instance attributes. You don't need little markers on data names to suggest nominal privacy on attribute variables or hash keys, because these are B notionally private! Outsiders have no business whatsoever playing with anything within a class save through the mediated access of its documented interface; in other words, through method invocations. And not even through just any method, either. Methods that begin with an underscore are traditionally considered off-limits outside the class. If outsiders skip the documented method interface to poke around the internals of your class and end up breaking something, that's not your fault--it's theirs. =end original Perlプログラマの幾人かに使われている慣習とは違い、先の例では、 クラス属性に使われるパッケージ変数の前に、アンダースコアを付けていませんし、 インスタンス属性に使われるハッシュキーの名前にも、そのようにしていません。 データの名前に小さなマークをつけて、属性変数や、ハッシュのキーに、名目上の プライバシーを暗示する必要はありません; というのは、B<いつも> 概念的に プライベートだからです! 部外者が、クラス内で何かをいじるかは、少しも気にしなく良いからです。 そのドキュメントのインターフェースを通すのを除いて;言い換えると、メソッドの 実行を通すのを除いて。 そして、単に任意のメソッドを通して、というわけでもありません。 下線で始まるメソッドは伝統的に、クラスの外側から立入禁止と考えられています。 もし、部外者が、ドキュメントに書かれたメソッドインターフェースを読み飛ばして、 部外者が、クラスの内部をつつきまわすために文書化されている メソッドインターフェースを飛ばして、何かを壊すことになっても、クラスの作者の 落度ではありません。 -- それは、そういうことをした部外者の落度です。 =begin original Perl believes in individual responsibility rather than mandated control. Perl respects you enough to let you choose your own preferred level of pain, or of pleasure. Perl believes that you are creative, intelligent, and capable of making your own decisions--and fully expects you to take complete responsibility for your own actions. In a perfect world, these admonitions alone would suffice, and everyone would be intelligent, responsible, happy, and creative. And careful. One probably shouldn't forget careful, and that's a good bit harder to expect. Even Einstein would take wrong turns by accident and end up lost in the wrong part of town. =end original Perl は、統治された制御よりもむしろ、個人の責務を信じています。 Perl は十分にあなたを尊敬しているので、あなたに、自身にあったレベルの痛みや 喜びを選択させます。 Perl は、あなたが、創造的で、知性的で、自分自身で決定でき--そして自身の 行動に完全に責任を取れると期待しています。 完全な世界では、このような勧告だけで十分でしょう。 そして、全ての人が、知性的で、信頼でき、幸福で、創造的であるでしょう。 そして、慎重にしてください。 たぶんある人が慎重であることを忘れても、それは、かなり 予測しがたいことでしょう。 アインシュタインでさえ、うっかり曲がり間違えて、町の間違った地域で 迷うことになりました。 =begin original Some folks get the heebie-jeebies when they see package variables hanging out there for anyone to reach over and alter them. Some folks live in constant fear that someone somewhere might do something wicked. The solution to that problem is simply to fire the wicked, of course. But unfortunately, it's not as simple as all that. These cautious types are also afraid that they or others will do something not so much wicked as careless, whether by accident or out of desperation. If we fire everyone who ever gets careless, pretty soon there won't be anybody left to get any work done. =end original 誰でも、パッケージ変数に、手が届き、変更できる、出入りできる、 パッケージ変数に、とても神経質になる人もいます。 誰かが、どこかで、 悪戯をすることに、不断に帯得ている人達です。 この問題の解決は単純に、悪戯を押え込むことです、もちろん。 ですが、不幸なことに、そなんに簡単ではありません。 これらの警告タイプは、彼らや他の人々が、たまたまか、絶望の中からかどうか、 注意なしにそんなにひどくない悪戯をするのにも恐れさせます。 注意不足な人々みんなを解雇するするなら、そこには、すぐに、何かの仕事をする 人は誰も居なくなるでしょう。 =begin original Whether it's needless paranoia or sensible caution, this uneasiness can be a problem for some people. We can take the edge off their discomfort by providing the option of storing class attributes as lexical variables instead of as package variables. The my() operator is the source of all privacy in Perl, and it is a powerful form of privacy indeed. =end original それが、必要のないパラノイアか、賢明な警告かどうか、 この不安は人によっては、問題になりえます。 パッケージ変数の代わりにレキシカル変数に、クラス属性を蓄えるオプションを 与えることで、そういう人たちの不安を和らげることができます。 my() 演算子は Perl のすべてのプライバシーの源です。 そして、my() は、プライバシーの強力な形です。 実際に。 =begin original It is widely perceived, and indeed has often been written, that Perl provides no data hiding, that it affords the class designer no privacy nor isolation, merely a rag-tag assortment of weak and unenforceable social conventions instead. This perception is demonstrably false and easily disproven. In the next section, we show how to implement forms of privacy that are far stronger than those provided in nearly any other object-oriented language. =end original 次のことは、広く認められていますし、実際、よく書かれています。 Perlは、データの隠蔽を提供しないし、 Perlは、クラスの設計者にプライバシーも孤立も提供しません。 単に、ぼろぎれの、弱点の詰め合わせであり、 押しつけることの出来ない社会的慣習が代わりにあるだけです。 この認識は、確実に間違いであり、ちっとも精査されていません。 次のセクションでは、ほとんどのどんな他のオブジェクト指向言語で 提供されているよりも、はるかに強力なプライバシーの形を実装するのを見せます。 =head2 File-Scoped Lexicals (ファイルスコープのレキシカル変数) =begin original A lexical variable is visible only through the end of its static scope. That means that the only code able to access that variable is code residing textually below the my() operator through the end of its block if it has one, or through the end of the current file if it doesn't. =end original レキシカル変数はその静的なスコープの終りまででしか、見えません。 このことは、ブロックがあればそのブロックの終りまでの、ブロックがなければ 現在のファイルの終りまでの、my() 演算子の下にあるテキストに存在する コードだけが、この変数にアクセス出来る唯一のコードです。 =begin original Starting again with our simplest example given at the start of this document, we replace our() variables with my() versions. =end original このドキュメントの最初にあった、最も単純な例で始めましょう。 our() 変数を my() バージョンで置き換えます。 package Some_Class; my($CData1, $CData2); # file scope, not in any package sub CData1 { shift; # XXX: ignore calling class/object $CData1 = shift if @_; return $CData1; } sub CData2 { shift; # XXX: ignore calling class/object $CData2 = shift if @_; return $CData2; } =begin original So much for that old $Some_Class::CData1 package variable and its brethren! Those are gone now, replaced with lexicals. No one outside the scope can reach in and alter the class state without resorting to the documented interface. Not even subclasses or superclasses of this one have unmediated access to $CData1. They have to invoke the &CData1 method against Some_Class or an instance thereof, just like anybody else. =end original あの古い、$Some_Class::CData1 パッケージ変数とその仲間については、 これだけにしておきます! それらは、今や過ぎさって、レキシカル変数に置き換えられました。 スコープの外側にいる誰も、ドキュメントに書かれたインターフェースの手段以外に、 クラスの状態に影響を及ぼせませんし、変更も出来ません。 このサブクラスやスーパークラスでさえ、$CData1 へアクセスを仲介しません。 Some_Class か、そのインスタンスか、他の似たようなもので、 &CData1 メソッドを呼ぶ必要があります。 =begin original To be scrupulously honest, that last statement assumes you haven't packed several classes together into the same file scope, nor strewn your class implementation across several different files. Accessibility of those variables is based uniquely on the static file scope. It has nothing to do with the package. That means that code in a different file but the same package (class) could not access those variables, yet code in the same file but a different package (class) could. There are sound reasons why we usually suggest a one-to-one mapping between files and packages and modules and classes. You don't have to stick to this suggestion if you really know what you're doing, but you're apt to confuse yourself otherwise, especially at first. =end original ものすごく正直になれば、最後のステートメントは、同じファイルスコープに、 複数のクラスを一緒にパックしないし、複数の違うファイルにまたがって、クラスの 実装ばらまきもしないと想定するでしょう。 これらの変数のアクセシビリティは、静的なファイルスコープでユニークに ベースにされています。 =begin original If you'd like to aggregate your class attributes into one lexically scoped, composite structure, you're perfectly free to do so. =end original クラス属性を 1 つのレキシカルスコープの変数に集約し、構造体を作りたければ、 そうするのは、完全に自由です。 package Some_Class; my %ClassData = ( CData1 => "", CData2 => "", ); sub CData1 { shift; # XXX: ignore calling class/object $ClassData{CData1} = shift if @_; return $ClassData{CData1}; } sub CData2 { shift; # XXX: ignore calling class/object $ClassData{CData2} = shift if @_; return $ClassData{CData2}; } =begin original To make this more scalable as other class attributes are added, we can again register closures into the package symbol table to create accessor methods for them. =end original 他のクラス属性を加えるように、より拡張性をもたせたければ、 再び、パッケージのシンボルテーブルにクロージャを登録し、 それらのためのアクセスメソッドを作れます。 package Some_Class; my %ClassData = ( CData1 => "", CData2 => "", ); for my $datum (keys %ClassData) { no strict "refs"; *$datum = sub { shift; # XXX: ignore calling class/object $ClassData{$datum} = shift if @_; return $ClassData{$datum}; }; } =begin original Requiring even your own class to use accessor methods like anybody else is probably a good thing. But demanding and expecting that everyone else, be they subclass or superclass, friend or foe, will all come to your object through mediation is more than just a good idea. It's absolutely critical to the model. Let there be in your mind no such thing as "public" data, nor even "protected" data, which is a seductive but ultimately destructive notion. Both will come back to bite at you. That's because as soon as you take that first step out of the solid position in which all state is considered completely private, save from the perspective of its own accessor methods, you have violated the envelope. And, having pierced that encapsulating envelope, you shall doubtless someday pay the price when future changes in the implementation break unrelated code. Considering that avoiding this infelicitous outcome was precisely why you consented to suffer the slings and arrows of obsequious abstraction by turning to object orientation in the first place, such breakage seems unfortunate in the extreme. =end original 何か他のようなアクセサメソッドを使う自分自身のクラスを必要とすることは、 おそらく良い事です。ですが、他のもの全て、サブクラス、スーパークラス、 敵味方、全てが、仲介を通してあなたのオブジェクトにくるのを、 要求したり、予期したりすることは、単なる良い考えを超えるものです。 これは、そのモデルにとって全く重要です。 "public" データも、"protected" データも、どちらも、 そのようなものは心の中からなくしましょう。 それらは、魅惑的ですが、詰まるところ、有害な考えです。 両方とも、戻って来て、あなたに噛みつくでしょう。 全ての状態が完全にプライベートだと考えられ、それ自身のアクセサメソッドの 観点から保存される、安定した位置から外れるとすぐに、そのエンベロープを 破ることになるからです。 カプセル化されているエンベロープに穴を開けていると、 未来の実装の変更が関係ないコードを壊す時、誰かが代価を払うことは、 間違いありません。 この不完全な結果を避ける考えは、まさに、最初の場所でオブジェクト志向に 変化することによる卑屈な抽象化の批判を被るのに納得する理由であり、 そのような破損はとても残念なことに思えます。 =head2 More Inheritance Concerns (より多くの継承の懸念) =begin original Suppose that Some_Class were used as a base class from which to derive Another_Class. If you invoke a &CData method on the derived class or on an object of that class, what do you get? Would the derived class have its own state, or would it piggyback on its base class's versions of the class attributes? =end original Some_Class が、派生の Another_Class から基底クラスとして 使われているとしましょう。 &CData メソッドを、派生クラスか、派生クラスのオブジェクトで呼んだら、 何を得るでしょうか? 派生クラスは、その自身の状態があるのか、それとも、 基底クラスのクラス属性の変数におんぶするのでしょうか? =begin original The answer is that under the scheme outlined above, the derived class would B have its own state data. As before, whether you consider this a good thing or a bad one depends on the semantics of the classes involved. =end original その答えは上で要点をまとめた枠組のもとにあります。 派生クラスはそれ自身の状態データがあり B<ません>。 前のように、これを良いことと思うか、悪いことと思うか、 関係するクラスの意味によります。 =begin original The cleanest, sanest, simplest way to address per-class state in a lexical is for the derived class to override its base class's version of the method that accesses the class attributes. Since the actual method called is the one in the object's derived class if this exists, you automatically get per-class state this way. Any urge to provide an unadvertised method to sneak out a reference to the %ClassData hash should be strenuously resisted. =end original レキシカルで、クラスごとの状態を扱う、最も綺麗な、最も健全で、最も単純な 方法は、クラス属性にアクセスするメソッドの基底クラスのバージョンを 派生クラス用に、オーバーライドすることです。 呼び出される実際のメソッドが、オブジェクトの派生クラスのものなので、 もしあれば、この方法で、クラス後との状態を時動的に得ます。 %ClassData ハッシュへのリファレンスをこっそり外に持ち出すめの、 非公式のメソッドを提供する衝動に、はげしく耐えるべきです。 =begin original As with any other overridden method, the implementation in the derived class always has the option of invoking its base class's version of the method in addition to its own. Here's an example: =end original 他のオーバーライドされたメソッドと同様に、派生クラスの実装にはいつも、 自分自身のバージョンとは別に、その基底クラスバージョンのメソッドを 呼び出すオプションがあります。 その例です: package Another_Class; @ISA = qw(Some_Class); my %ClassData = ( CData1 => "", ); sub CData1 { my($self, $newvalue) = @_; if (@_ > 1) { # set locally first $ClassData{CData1} = $newvalue; # then pass the buck up to the first # overridden version, if there is one if ($self->can("SUPER::CData1")) { $self->SUPER::CData1($newvalue); } } return $ClassData{CData1}; } =begin original Those dabbling in multiple inheritance might be concerned about there being more than one override. =end original オーバーライドよりも、多重継承に首をつっこむとが、考えられます。 for my $parent (@ISA) { my $methname = $parent . "::CData1"; if ($self->can($methname)) { $self->$methname($newvalue); } } =begin original Because the &UNIVERSAL::can method returns a reference to the function directly, you can use this directly for a significant performance improvement: =end original &UNIVERSAL::can メソッドは、関数へのリファレンスを、直接に返します。 ですので、重要なパフォーマンスの改良のために、これを直接に使うことが できます。 for my $parent (@ISA) { if (my $coderef = $self->can($parent . "::CData1")) { $self->$coderef($newvalue); } } =begin original If you override C in your own classes, be sure to return the reference appropriately. =end original C を自身のクラスでオーバーライドする場合は、確実に適切な リファレンスを返すようにしてください。 =head2 Locking the Door and Throwing Away the Key (ドアに施錠して、鍵を放り投げる) =begin original As currently implemented, any code within the same scope as the file-scoped lexical %ClassData can alter that hash directly. Is that ok? Is it acceptable or even desirable to allow other parts of the implementation of this class to access class attributes directly? =end original 現在インプリメントされるように、ファイルスコープのレキシカル変数の %ClassData と同じ範囲内のどのコードでも、そのハッシュを直接に、変更できます。 これは良いでしょうか? このクラスの実装の他の部分が、直接にクラス属性にアクセスすることを許すことは、 受け入れられか、望ましいものでしょうか? =begin original That depends on how careful you want to be. Think back to the Cosmos class. If the &supernova method had directly altered $Cosmos::Stars or C<$Cosmos::Cosmos{stars}>, then we wouldn't have been able to reuse the class when it came to inventing a Multiverse. So letting even the class itself access its own class attributes without the mediating intervention of properly designed accessor methods is probably not a good idea after all. =end original このことは、あなたがどれくらい注意深くありたいかに依存します。 Cosmo クラスに戻って、考えてください。 &supernova メソッドが直接に、$Cosmos::Starts か、 C<$colsmos::Cosmos{stars}> を変更していたら、Multiverse を考案するときに、 クラスを再利用することができなかったでしょう。 クラスそれ自身でさえも、そのクラス属性に、適切に設計されたアクセサメソッドが 仲介している介入なしに、アクセスするのは、結局、良い考えではないでしょう。 =begin original Restricting access to class attributes from the class itself is usually not enforceable even in strongly object-oriented languages. But in Perl, you can. =end original クラス自身からクラス属性へのアクセスを制限するのは、ふつう、 強力なオブジェクト指向言語でさえ、強制されていません。 ですが、Perl では、できます。 =begin original Here's one way: =end original 一つの方法です: package Some_Class; { # scope for hiding $CData1 my $CData1; sub CData1 { shift; # XXX: unused $CData1 = shift if @_; return $CData1; } } { # scope for hiding $CData2 my $CData2; sub CData2 { shift; # XXX: unused $CData2 = shift if @_; return $CData2; } } =begin original No one--absolutely no one--is allowed to read or write the class attributes without the mediation of the managing accessor method, since only that method has access to the lexical variable it's managing. This use of mediated access to class attributes is a form of privacy far stronger than most OO languages provide. =end original 誰も -- 絶対に誰も -- クラス属性に、支配しているアクセサメソッドの 仲介なしには、クラス属性を読み書きすることを許されていません。 メソッドだけが、支配ているレキシカル変数にアクセスするからです。 この、クラス属性への仲介するアクセスの使用は、ほとんどの、オブジェクト指向 言語が提供するものよりも、はるかに強力な、プライバシーの形です。 =begin original The repetition of code used to create per-datum accessor methods chafes at our Laziness, so we'll again use closures to create similar methods. =end original データごとの アクセサメソッドを作成するために使用される、コードを 反復するのは、不精を苛立だせるので、 似たようなメソッドを作成するのに、再びクロージャを使用しましょう。 package Some_Class; { # scope for ultra-private meta-object for class attributes my %ClassData = ( CData1 => "", CData2 => "", ); for my $datum (keys %ClassData ) { no strict "refs"; *$datum = sub { use strict "refs"; my ($self, $newvalue) = @_; $ClassData{$datum} = $newvalue if @_ > 1; return $ClassData{$datum}; } } } =begin original The closure above can be modified to take inheritance into account using the &UNIVERSAL::can method and SUPER as shown previously. =end original 上のクロージャは、以前に示した、&UNIVERSAL::can メソッドと SUPER を使用して、 継承を考慮に入れるために修正できます。 =head2 Translucency Revisited (半透明、再び) =begin original The Vermin class demonstrates translucency using a package variable, eponymously named %Vermin, as its meta-object. If you prefer to use absolutely no package variables beyond those necessary to appease inheritance or possibly the Exporter, this strategy is closed to you. That's too bad, because translucent attributes are an appealing technique, so it would be valuable to devise an implementation using only lexicals. =end original Veriman クラスは、そのメタオブジェクトとして、パッケージ変数、 クラスの名前の %Vermin を使って、半透明性をデモンストレーションしました。 継承か、もしかすると、Exporter を和らげるそれらの必需品以上に、 絶対に、パッケージでない変数を使いたいなら、この作戦は、身近なものです。 残念なことに、半透明の属性はアピールするテクニックですので、 レキシカル変数のみを使う実装を考え出す価値のあるものです。 =begin original There's a second reason why you might wish to avoid the eponymous package hash. If you use class names with double-colons in them, you would end up poking around somewhere you might not have meant to poke. =end original ここに、クラスの名前のハッシュを避けたいと思う 2 つ目の理由があります。 それらに、ダブルコロンのクラス名を使うと、 つつくつもりのないどこかを、結局、つつくことになるでしょう。 package Vermin; $class = "Vermin"; $class->{PopCount}++; # accesses $Vermin::Vermin{PopCount} package Vermin::Noxious; $class = "Vermin::Noxious"; $class->{PopCount}++; # accesses $Vermin::Noxious{PopCount} =begin original In the first case, because the class name had no double-colons, we got the hash in the current package. But in the second case, instead of getting some hash in the current package, we got the hash %Noxious in the Vermin package. (The noxious vermin just invaded another package and sprayed their data around it. :-) Perl doesn't support relative packages in its naming conventions, so any double-colons trigger a fully-qualified lookup instead of just looking in the current package. =end original 最初のケースでは、クラスの名前にはダブルコロンがなかったので、現在の パッケージのハッシュを得ました。 ですが、次のケースでは、現在のパッケージのハッシュを得る代わりに、 Vermin パッケージの、ハッシュ %Noxious を得ました。 (有毒な害虫は、他のパッケージに侵入し、そのまわりに、自分のデータを 撒き散らします :-) Perl の命名仕様は、相対パッケージを サポートしません。 ですので、ダブルコロンは、現在のパッケージの中を見るだけではなく、 完全修飾された検索を引き起こします。 =begin original In practice, it is unlikely that the Vermin class had an existing package variable named %Noxious that you just blew away. If you're still mistrustful, you could always stake out your own territory where you know the rules, such as using Eponymous::Vermin::Noxious or Hieronymus::Vermin::Boschious or Leave_Me_Alone::Vermin::Noxious as class names instead. Sure, it's in theory possible that someone else has a class named Eponymous::Vermin with its own %Noxious hash, but this kind of thing is always true. There's no arbiter of package names. It's always the case that globals like @Cwd::ISA would collide if more than one class uses the same Cwd package. =end original 実際問題、Vermin クラスには、吹き飛ばした、%Noxious という名前の、 存在するパッケージ変数は、ありそうもないです。 まだ、信用できないなら、ルールを知っている自分の領域を、つねに 見張ることができます。 Eponymous::Vermin::Noxious か、Hieronymus::Vermin::Boschious か、 Leave_Me_Alone::Vermin::Noxious を、クラス名として、代わりに、使うように。 確かに、 他の誰かが、Eponymous::Vermin という名のクラスを、 それ自身の %Noxious ハッシュと一緒に持つことは、理論上は可能ですが、 この種類のことは、つねに真実です。 パッケージの名前の得決定者はいません。 2 つ以上のクラスが同じ Cwd パッケージを使うなら、@Cwd::ISA のようなグローバル 変数が衝突するするのは、ありがちなケースです。 =begin original If this still leaves you with an uncomfortable twinge of paranoia, we have another solution for you. There's nothing that says that you have to have a package variable to hold a class meta-object, either for monadic classes or for translucent attributes. Just code up the methods so that they access a lexical instead. =end original パラノイアの不快な苦痛がまだ残っているなら、別の解決法があります。 一価のクラスのために、あるいは半透明の属性のために、 クラスのメタオブジェクトにを持つのに、パッケージ変数を 持たなくてはいけないとするものは何もありません。 代わりに、レキシカルにアクセスするようなメソッドをコードにしてください。 =begin original Here's another implementation of the Vermin class with semantics identical to those given previously, but this time using no package variables. =end original Vermin クラスの別の実装です。 以前に与えられたものと同じ意味ですが、今回は、パッケージ変数を 使っていません。 package Vermin; # Here's the class meta-object, eponymously named. # It holds all class data, and also all instance data # so the latter can be used for both initialization # and translucency. it's a template. my %ClassData = ( PopCount => 0, # capital for class attributes color => "beige", # small for instance attributes ); # constructor method # invoked as class method or object method sub spawn { my $obclass = shift; my $class = ref($obclass) || $obclass; my $self = {}; bless($self, $class); $ClassData{PopCount}++; # init fields from invoking object, or omit if # invoking object is the class to provide translucency %$self = %$obclass if ref $obclass; return $self; } # translucent accessor for "color" attribute # invoked as class method or object method sub color { my $self = shift; # handle class invocation unless (ref $self) { $ClassData{color} = shift if @_; return $ClassData{color} } # handle object invocation $self->{color} = shift if @_; if (defined $self->{color}) { # not exists! return $self->{color}; } else { return $ClassData{color}; } } # class attribute accessor for "PopCount" attribute # invoked as class method or object method sub population { return $ClassData{PopCount}; } # instance destructor; invoked only as object method sub DESTROY { $ClassData{PopCount}--; } # detect whether an object attribute is translucent # (typically?) invoked only as object method sub is_translucent { my($self, $attr) = @_; $self = \%ClassData if !ref $self; return !defined $self->{$attr}; } # test for presence of attribute in class # invoked as class method or object method sub has_attribute { my($self, $attr) = @_; return exists $ClassData{$attr}; } =head1 NOTES (注意) =begin original Inheritance is a powerful but subtle device, best used only after careful forethought and design. Aggregation instead of inheritance is often a better approach. =end original 継承は強力ですが、繊細な仕組みです。 注意深い見通しと設計の後で使うのが一番です。 継承の代わりに、集約が、よりよいアプローチであることがよくあります。 =begin original You can't use file-scoped lexicals in conjunction with the SelfLoader or the AutoLoader, because they alter the lexical scope in which the module's methods wind up getting compiled. =end original SelfLoader か、AutoLoader との接続では、ファイルスコープのレキシカル変数を 使えません。 モジュールのメソッドが、結局コンパイルされるレキシカルスコープを 変更するからです。 =begin original The usual mealy-mouthed package-munging doubtless applies to setting up names of object attributes. For example, C<< $self->{ObData1} >> should probably be C<< $self->{ __PACKAGE__ . "_ObData1" } >>, but that would just confuse the examples. =end original ふつう当り障りのない、パッケージのマンジングは、確かに、オブジェクト属性の 名前をセットするのに、適合します。 たとえば、C<< $self->{ObData1} >> は、おそらく、 C<< $self->{ __PACKAGE__ . "_ObData1" } >> であるべきです。 ですが、それは、例を混乱させるだけだったでしょう、 =head1 SEE ALSO =begin original L, L, L, and L. =end original L, L, L, L。 =begin original The Tie::SecureHash and Class::Data::Inheritable modules from CPAN are worth checking out. =end original CPAN にある Tie::SecureHash と、Class::Data::Inheritable モジュールは、 良く調べる価値があります。 =head1 AUTHOR AND COPYRIGHT (著者と著作権) Copyright (c) 1999 Tom Christiansen. All rights reserved. This documentation is free; you can redistribute it and/or modify it under the same terms as Perl itself. Irrespective of its distribution, all code examples in this file are hereby placed into the public domain. You are permitted and encouraged to use this code in your own programs for fun or for profit as you see fit. A simple comment in the code giving credit would be courteous but is not required. =head1 ACKNOWLEDGEMENTS (謝辞) Russ Allbery, Jon Orwant, Randy Ray, Larry Rosler, Nat Torkington, and Stephen Warren all contributed suggestions and corrections to this piece. Thanks especially to Damian Conway for his ideas and feedback, and without whose indirect prodding I might never have taken the time to show others how much Perl has to offer in the way of objects once you start thinking outside the tiny little box that today's "popular" object-oriented languages enforce. =head1 HISTORY (履歴) Last edit: Sun Feb 4 20:50:28 EST 2001 =begin meta Translate: Kato Atsushi (5.8.0) Update: SHIRAKATA Kentaro (5.10.0-) Status: completed =end meta