5.30.0

名前

perlootut - Object-Oriented Programming in Perl Tutorial

perlootut - Perl でのオブジェクト指向プログラミングのチュートリアル

DATE

This document was created in February, 2011, and the last major revision was in February, 2013.

この文書は 2011 年 2 月に作成され、最後に大きく見直されたのは 2013 年 2 月です。

If you are reading this in the future then it's possible that the state of the art has changed. We recommend you start by reading the perlootut document in the latest stable release of Perl, rather than this version.

もし将来これを読んでいる場合、最新版は変更されている可能性があります。 このバージョンではなく、Perl の最新安定リリースの perlootut 文書を 読むことから始めることを勧めます。

説明

This document provides an introduction to object-oriented programming in Perl. It begins with a brief overview of the concepts behind object oriented design. Then it introduces several different OO systems from CPAN which build on top of what Perl provides.

この文書は Perl でのオブジェクト指向プログラミングを紹介します。 これはオブジェクト指向設計の背後にあるコンセプトの概説から始めます。 それから Perl が提供するものの上に構築されている、 CPAN にあるいくつかの OO システムを紹介します。

By default, Perl's built-in OO system is very minimal, leaving you to do most of the work. This minimalism made a lot of sense in 1994, but in the years since Perl 5.0 we've seen a number of common patterns emerge in Perl OO. Fortunately, Perl's flexibility has allowed a rich ecosystem of Perl OO systems to flourish.

デフォルトでは、Perl の組み込みの OO システムはとても最小限です; ほとんどの 作業を自分でする必要があります。 この最小限主義は 1994 年には十分意味のあるものでしたが、Perl 5.0 から 時が経つにつれて、Perl OO に多くの共通のパターンが見られるようになりました。 幸い、Perl の柔軟性により、Perl OO システムの豊かなエコシステムが 発展しました。

If you want to know how Perl OO works under the hood, the perlobj document explains the nitty gritty details.

裏で Perl OO がどのように動作するのかを知りたい場合は、perlobj 文書が 本質的な詳細について説明しています。

This document assumes that you already understand the basics of Perl syntax, variable types, operators, and subroutine calls. If you don't understand these concepts yet, please read perlintro first. You should also read the perlsyn, perlop, and perlsub documents.

この文書は、Perl の文法、変数型、演算子、サブルーチン呼び出しの基本について 既に理解していると仮定しています。 まだこれらのコンセプトについてまだ理解していないなら、まず perlintro を 読んでください。 perlsyn, perlop, perlsub 文書も読むべきでしょう。

オブジェクト指向の基本

Most object systems share a number of common concepts. You've probably heard terms like "class", "object, "method", and "attribute" before. Understanding the concepts will make it much easier to read and write object-oriented code. If you're already familiar with these terms, you should still skim this section, since it explains each concept in terms of Perl's OO implementation.

ほとんどのオブジェクトシステムは多くの共通の概念を共有しています。 おそらく以前に「クラス」、「オブジェクト」、「メソッド」、属性といった 用語について聞いたことがあるでしょう。 概念の理解は、オブジェクト指向のコードを読み書きするよりも遥かに容易です。 既にこれらの用語に親しんでいても、この章に目を通すべきです; なぜなら Perl の OO 実装の用語でそれぞれの概念を説明しているからです。

Perl's OO system is class-based. Class-based OO is fairly common. It's used by Java, C++, C#, Python, Ruby, and many other languages. There are other object orientation paradigms as well. JavaScript is the most popular language to use another paradigm. JavaScript's OO system is prototype-based.

Perl の OO システムはクラスベースです。 クラスベース OO はかなり一般的です。 これは Java, C++, C#, Python, Ruby およびその他の多くの言語で使われています。 その他のオブジェクト指向パラダイムもあります。 JavaScript は、その他のパラダイムを使っている最も有名な言語です。 JavaScript の OO システムはプロトタイプベースです。

オブジェクト

An object is a data structure that bundles together data and subroutines which operate on that data. An object's data is called attributes, and its subroutines are called methods. An object can be thought of as a noun (a person, a web service, a computer).

オブジェクト は、データと、そのデータを操作するサブルーチンを一つに まとめたデータ構造です。 オブジェクトのデータは 属性 と呼ばれ、サブルーチンは メソッド と 呼ばれます。 オブジェクトは名詞と考えることができます (人、web サービス、 コンピュータなど)。

An object represents a single discrete thing. For example, an object might represent a file. The attributes for a file object might include its path, content, and last modification time. If we created an object to represent /etc/hostname on a machine named "foo.example.com", that object's path would be "/etc/hostname", its content would be "foo\n", and it's last modification time would be 1304974868 seconds since the beginning of the epoch.

オブジェクトは単一のものを表現します。 たとえば、あるオブジェクトがファイルを表現しているとします。 ファイルオブジェクトの属性はパス、内容、最終更新時刻といったものになります。 オブジェクトのパスが "/etc/hostname" になるような、 "foo.example.com" という名前のマシンの /etc/hostname を表現する オブジェクトを作る場合、その内容は "foo\n" で、最終更新時刻は紀元から 1304974868 秒といったものになります。

The methods associated with a file might include rename() and write().

ファイルに結びつけられたメソッドは rename()write() と いったものになります。

In Perl most objects are hashes, but the OO systems we recommend keep you from having to worry about this. In practice, it's best to consider an object's internal data structure opaque.

Perl ではほとんどのオブジェクトはハッシュですが、推奨する OO システムは これについて気にする必要がないようにします。 実際には、オブジェクトの内部構造は不透明であると考えるのが最良です。

クラス

A class defines the behavior of a category of objects. A class is a name for a category (like "File"), and a class also defines the behavior of objects in that category.

クラス はあるカテゴリのオブジェクトの振る舞いを定義します。 クラスは("File" のような)カテゴリを表す名前です; またクラスは そのカテゴリのオブジェクトの振る舞いを定義します。

All objects belong to a specific class. For example, our /etc/hostname object belongs to the File class. When we want to create a specific object, we start with its class, and construct or instantiate an object. A specific object is often referred to as an instance of a class.

全てのオブジェクトは何らかのクラスに属します。 例えば、/etc/hostname オブジェクトは File クラスに属します。 特定のオブジェクトを作りたい場合、そのクラスから始めて、オブジェクトを 構築(construct) または インスタンス化 (instantiate) します。 特定のオブジェクトはしばしばクラスの インスタンス (instance) と 呼ばれます。

In Perl, any package can be a class. The difference between a package which is a class and one which isn't is based on how the package is used. Here's our "class declaration" for the File class:

Perl では、どのパッケージもクラスになれます。 クラスであるパッケージとそうでないパッケージの違いは、パッケージがどのように 使われるかによります。 以下は File クラスのための「クラス宣言」です:

  package File;

In Perl, there is no special keyword for constructing an object. However, most OO modules on CPAN use a method named new() to construct a new object:

Perl では、オブジェクトの構築のための特別なキーワードはありません。 しかし、CPAN のほとんどの OO モジュールは、新しいオブジェクトの構築に new() という名前のメソッドを使います:

  my $hostname = File->new(
      path          => '/etc/hostname',
      content       => "foo\n",
      last_mod_time => 1304974868,
  );

(Don't worry about that -> operator, it will be explained later.)

(-> 演算子について心配しないでください; 後で説明します。)

bless

As we said earlier, most Perl objects are hashes, but an object can be an instance of any Perl data type (scalar, array, etc.). Turning a plain data structure into an object is done by blessing that data structure using Perl's bless function.

既に述べたように、ほとんどの Perl オブジェクトはハッシュですが、 オブジェクトはどの Perl データ型 (スカラ、配列など)のインスタンスも可能です。 普通のデータ構造のオブジェクトへの変換は、データ構造に Perl の bless 関数を 使うことによる bless によって行われます。

While we strongly suggest you don't build your objects from scratch, you should know the term bless. A blessed data structure (aka "a referent") is an object. We sometimes say that an object has been "blessed into a class".

一からオブジェクトを構築しないことを強く勧めますが、bless という 用語は知っておくべきです。 bless された データ構造 (またの名を「リファレンス先」)はオブジェクトです。 時々、オブジェクトは「クラスに bless された」と表現します。

Once a referent has been blessed, the blessed function from the Scalar::Util core module can tell us its class name. This subroutine returns an object's class when passed an object, and false otherwise.

一旦リファレンス先が bless されると、Scalar::Util コアモジュールの blessed 関数はそのクラス名を返します。 このサブルーチンは、オブジェクトが和されるとオブジェクトのクラスを返し、 さもなければ偽を返します。

  use Scalar::Util 'blessed';

  print blessed($hash);      # undef
  print blessed($hostname);  # File

コンストラクタ

A constructor creates a new object. In Perl, a class's constructor is just another method, unlike some other languages, which provide syntax for constructors. Most Perl classes use new as the name for their constructor:

コンストラクタ は新しいオブジェクトを作成します。 コンストラクタのための文法を提供しているその他の言語と異なり、Perl では クラスのコンストラクタは単なるメソッドです。 ほとんどの Perl クラスはコンストラクタの名前として new を使います:

  my $file = File->new(...);

メソッド

You already learned that a method is a subroutine that operates on an object. You can think of a method as the things that an object can do. If an object is a noun, then methods are its verbs (save, print, open).

オブジェクトを操作するサブルーチンが メソッド であるということは 既に学んでいます。 メソッドはオブジェクトが する ことと考えることができます。 オブジェクトが名詞なら、メソッドは動詞 (保存する、表示する、開く) です。

In Perl, methods are simply subroutines that live in a class's package. Methods are always written to receive the object as their first argument:

Perl では、メソッドは単にクラスのパッケージにあるサブルーチンです。 メソッドは常に最初の引数としてオブジェクトを受け取るように書かれます:

  sub print_info {
      my $self = shift;

      print "This file is at ", $self->path, "\n";
  }

  $file->print_info;
  # The file is at /etc/hostname

What makes a method special is how it's called. The arrow operator (->) tells Perl that we are calling a method.

メソッドを特別なものにしているのは、どのように呼び出されるか です。 矢印演算子 (->) は、メソッドとして呼び出していることを Perl に 知らせます。

When we make a method call, Perl arranges for the method's invocant to be passed as the first argument. Invocant is a fancy name for the thing on the left side of the arrow. The invocant can either be a class name or an object. We can also pass additional arguments to the method:

メソッド呼び出しをするとき、Perl はメソッドの 呼び出し元 (invocant) を 最初の引数として渡すように用意します。 to be passed as the first argument. 呼び出し元 とは矢印の左側にあるものの名前です。 呼び出し元はクラス名とオブジェクトのどちらかです。 また、メソッドに追加の引数も渡せます:

  sub print_info {
      my $self   = shift;
      my $prefix = shift // "This file is at ";

      print $prefix, ", ", $self->path, "\n";
  }

  $file->print_info("The file is located at ");
  # The file is located at /etc/hostname

属性

Each class can define its attributes. When we instantiate an object, we assign values to those attributes. For example, every File object has a path. Attributes are sometimes called properties.

各クラスは 属性 を定義します。 オブジェクトをインスタンス化するとき、これらの属性に値を代入します。 例えば、各 File オブジェクトはパスを持ちます。 属性は時々 プロパティ (properties) と呼ばれます。

Perl has no special syntax for attributes. Under the hood, attributes are often stored as keys in the object's underlying hash, but don't worry about this.

Perl には属性のための特別な文法はありません。 内部では、属性はしばしばオブジェクトの基となっているハッシュのキーとして 保管されますが、これについて気にすることはありません。

We recommend that you only access attributes via accessor methods. These are methods that can get or set the value of each attribute. We saw this earlier in the print_info() example, which calls $self->path.

属性には アクセサ (accessor) メソッドを経由してのみアクセスすることを 勧めます。 これはそれぞれの属性の値を取得または設定するメソッドです。 既に、前述した print_info() の例で、$self->path を 呼び出しているのを見ています。

You might also see the terms getter and setter. These are two types of accessors. A getter gets the attribute's value, while a setter sets it. Another term for a setter is mutator

ゲッター (getter) と セッター (setter) という用語も見るかも知れません。 これらはアクセサの種類です。 ゲッターは属性の値を取得し、セッターは設定します。 セッターに関する別名は ミューテータ (mutator) です。

Attributes are typically defined as read-only or read-write. Read-only attributes can only be set when the object is first created, while read-write attributes can be altered at any time.

属性は典型的には読み込み専用または読み書き可能として定義されます。 読み込み専用属性はオブジェクトが最初に作成されるときにのみ設定でき、 読み書き可能属性はいつでも変更できます。

The value of an attribute may itself be another object. For example, instead of returning its last mod time as a number, the File class could return a DateTime object representing that value.

属性の値それ自身が他のオブジェクトかも知れません。 例えば、最終更新時刻を数値として返す代わりに、File クラスはその値を 表現する DateTime オブジェクトを返すかも知れません。

It's possible to have a class that does not expose any publicly settable attributes. Not every class has attributes and methods.

設定可能な属性が一切公開されていないクラスも可能です。 全てのクラスが属性とメソッドを持っているというわけではありません。

多態性

Polymorphism is a fancy way of saying that objects from two different classes share an API. For example, we could have File and WebPage classes which both have a print_content() method. This method might produce different output for each class, but they share a common interface.

多態性 (polymorphism) は二つの異なるクラスが API を共有しているということを 示す変わった方法です。 例えば、どちらも print_content() メソッドを持つ、File クラスと WebPage クラスを持てます。 このメソッドはクラスごとに異なった出力を生成するかも知れませんが、共通の インターフェースを共有します。

While the two classes may differ in many ways, when it comes to the print_content() method, they are the same. This means that we can try to call the print_content() method on an object of either class, and we don't have to know what class the object belongs to!

二つのクラスはいろいろな意味で異なっているかも知れませんが、 print_content() メソッドを呼び出すときには、これらは同じです。 これは、どちらのクラスのオブジェクトに対しても print_content() を 呼び出そうとすることができて、オブジェクトがどのクラスに属しているかを 知る必要がないと言うことです!

Polymorphism is one of the key concepts of object-oriented design.

多態性はオブジェクト指向設計の鍵となる概念の一つです。

継承

Inheritance lets you create a specialized version of an existing class. Inheritance lets the new class reuse the methods and attributes of another class.

継承 は既にあるクラスの特殊版を作成できるようにします。 継承は他のクラスのメソッドと属性を再利用して新しいクラスを 作成できるようにします。

For example, we could create an File::MP3 class which inherits from File. An File::MP3 is-a more specific type of File. All mp3 files are files, but not all files are mp3 files.

例えば、File から 継承 した File::MP3 クラスを作成できます。 File::MP3 (is-a) Fileより特殊な 型です。 全ての mp3 ファイルはファイルですが、全てのファイルが mp3 ファイルというわけではありません。.

We often refer to inheritance relationships as parent-child or superclass/subclass relationships. Sometimes we say that the child has an is-a relationship with its parent class.

継承関係はしばしば 親-子 または スーパークラス/サブクラス 関係として 参照されます。 子は親クラスとの is-a 関係を持つと表現することがあります。

File is a superclass of File::MP3, and File::MP3 is a subclass of File.

FileFile::MP3スーパークラス で、File::MP3Fileサブクラス です。

  package File::MP3;

  use parent 'File';

The parent module is one of several ways that Perl lets you define inheritance relationships.

parent モジュールは、Perl で継承関係を定義するいくつかの方法のひとつです。

Perl allows multiple inheritance, which means that a class can inherit from multiple parents. While this is possible, we strongly recommend against it. Generally, you can use roles to do everything you can do with multiple inheritance, but in a cleaner way.

Perl は多重継承を認めています; つまり、クラスは複数の親から継承できます。 これは可能ですが、行わないように強く勧めます。 一般的に、多重継承で行えることは全て、ロール を使うことでより きれいな形で行えます。

Note that there's nothing wrong with defining multiple subclasses of a given class. This is both common and safe. For example, we might define File::MP3::FixedBitrate and File::MP3::VariableBitrate classes to distinguish between different types of mp3 file.

あるクラスに対して複数のサブクラスを定義することは何も悪くないことに 注意してください。 これは一般的でかつ安全です。 例えば、mp3 ファイルの異なった種類を区別するために、 File::MP3::FixedBitrate クラスと File::MP3::VariableBitrate クラスを 定義できます。

メソッドのオーバーライドとメソッド解決

Inheritance allows two classes to share code. By default, every method in the parent class is also available in the child. The child can explicitly override a parent's method to provide its own implementation. For example, if we have an File::MP3 object, it has the print_info() method from File:

継承は二つのクラスでコードを共有できるようにします。 デフォルトでは、親クラスの全てのメソッドは子でも利用可能です。 子は、独自の実装を提供することで親のメソッドを明示的に オーバーライド (override) できます。 例えば、File::MP3 オブジェクトがあれば、File からの print_info() メソッドがあります:

  my $cage = File::MP3->new(
      path          => 'mp3s/My-Body-Is-a-Cage.mp3',
      content       => $mp3_data,
      last_mod_time => 1304974868,
      title         => 'My Body Is a Cage',
  );

  $cage->print_info;
  # The file is at mp3s/My-Body-Is-a-Cage.mp3

If we wanted to include the mp3's title in the greeting, we could override the method:

返り値に mp3 のタイトルを含めたい場合、メソッドをオーバーライドできます:

  package File::MP3;

  use parent 'File';

  sub print_info {
      my $self = shift;

      print "This file is at ", $self->path, "\n";
      print "Its title is ", $self->title, "\n";
  }

  $cage->print_info;
  # The file is at mp3s/My-Body-Is-a-Cage.mp3
  # Its title is My Body Is a Cage

The process of determining what method should be used is called method resolution. What Perl does is look at the object's class first (File::MP3 in this case). If that class defines the method, then that class's version of the method is called. If not, Perl looks at each parent class in turn. For File::MP3, its only parent is File. If File::MP3 does not define the method, but File does, then Perl calls the method in File.

どのメソッドが使われるべきかを決定する処理は、メソッド解決 (method resolution) と呼ばれます。 Perl が行うことは、まずオブジェクトのクラス (この場合は File::MP3) を 見ます。 このクラスにメソッドが定義されていれば、そのクラスのメソッドが呼び出されます。 さもなければ、Perl は順番に親クラスを見ます。 File::MP3 の場合、唯一の親は File です。 File::MP3 がメソッドを定義しておらず、File が定義しているなら、 Perl は File のメソッドを呼び出します。

If File inherited from DataSource, which inherited from Thing, then Perl would keep looking "up the chain" if necessary.

FileDataSource から継承され、これが Thing から継承されていれば、 Perl はもし必要なら「チェーンをたどって」探し続けます。

It is possible to explicitly call a parent method from a child:

子から親メソッドを明示的に呼び出すことは可能です:

  package File::MP3;

  use parent 'File';

  sub print_info {
      my $self = shift;

      $self->SUPER::print_info();
      print "Its title is ", $self->title, "\n";
  }

The SUPER:: bit tells Perl to look for the print_info() in the File::MP3 class's inheritance chain. When it finds the parent class that implements this method, the method is called.

SUPER:: は、File::MP3 クラスの継承チェーンから print_info() を 探すように Perl に伝えます。 このメソッドを実装している親クラスが見つかると、そのメソッドが 呼び出されます。

We mentioned multiple inheritance earlier. The main problem with multiple inheritance is that it greatly complicates method resolution. See perlobj for more details.

以前に多重継承について述べました。 多重継承の主な問題は、メソッド解決が非常に込み入っているということです。 さらなる詳細については perlobj を参照してください。

カプセル化

Encapsulation is the idea that an object is opaque. When another developer uses your class, they don't need to know how it is implemented, they just need to know what it does.

カプセル化 は、オブジェクトを不透明にする考え方です。 他の開発者があなたのクラスを使うとき、どのように 実装されているかを 知る必要はなく、単に 何を するかを知る必要があるだけです。

Encapsulation is important for several reasons. First, it allows you to separate the public API from the private implementation. This means you can change that implementation without breaking the API.

カプセル化はいくつかの理由で重要です。 まず、これにより公的な API を内部の実装から分離できます。 これにより、API を壊すことなく実装を変更できます。

Second, when classes are well encapsulated, they become easier to subclass. Ideally, a subclass uses the same APIs to access object data that its parent class uses. In reality, subclassing sometimes involves violating encapsulation, but a good API can minimize the need to do this.

次に、クラスが十分にカプセル化されていれば、サブクラス化が容易になります。 理想的には、サブクラスは親クラスが使っているオブジェクトデータに アクセスするのに同じ API を使います。 実際には、サブクラス化は時々カプセル化に違反しますが、よい API は その必要性を最小限にします。

We mentioned earlier that most Perl objects are implemented as hashes under the hood. The principle of encapsulation tells us that we should not rely on this. Instead, we should use accessor methods to access the data in that hash. The object systems that we recommend below all automate the generation of accessor methods. If you use one of them, you should never have to access the object as a hash directly.

既に、ほとんどの Perl オブジェクトは内部ではハッシュとして実装されていると 述べました。 カプセル化の原則は、このことに依存するべきではないと伝えています。 代わりに、ハッシュのデータにアクセスするためにアクセサメソッドを使います。 後に推奨するオブジェクトシステムは全てアクセサメソッドの生成を自動化します。 これらの一つを使うなら、オブジェクトをハッシュとして直接アクセスする必要は ないはずです。

包含

In object-oriented code, we often find that one object references another object. This is called composition, or a has-a relationship.

オブジェクト指向のコードでは、しばしばあるオブジェクトが他のオブジェクトを 参照しています。 これは 包含 (composition)、または has-a 関係と呼ばれます。

Earlier, we mentioned that the File class's last_mod_time accessor could return a DateTime object. This is a perfect example of composition. We could go even further, and make the path and content accessors return objects as well. The File class would then be composed of several other objects.

既に、File クラスの last_mod_time アクセサが DateTime オブジェクトを 返すかも知れないことに触れました。 これは包含の完璧な例です。 さらに進めて、pathcontent アクセサもオブジェクトを返すようにも できます。 そして File クラスはいくつかのその他のオブジェクトの 包含 になります。

ロール

Roles are something that a class does, rather than something that it is. Roles are relatively new to Perl, but have become rather popular. Roles are applied to classes. Sometimes we say that classes consume roles.

ロール は、クラスが 何か ではなく、クラスが 何をするか です。 ロールは Perl では比較的新しいですが、かなり人気になってきています。 ロールはクラスに 適用 されます。 クラスがロールを 消費 (consume) するということもあります。

Roles are an alternative to inheritance for providing polymorphism. Let's assume we have two classes, Radio and Computer. Both of these things have on/off switches. We want to model that in our class definitions.

ロールは多態性を提供するための継承の代替策です。 二つのクラス RadioComputer があると考えます。 どちらもオン/オフするスイッチがあります。 これをクラス定義でモデル化したいとします。

We could have both classes inherit from a common parent, like Machine, but not all machines have on/off switches. We could create a parent class called HasOnOffSwitch, but that is very artificial. Radios and computers are not specializations of this parent. This parent is really a rather ridiculous creation.

Machine のように、共通の親から両方のクラスを継承することもできますが、 全ての機械にオン/オフスイッチがあるわけではありません。 HasOnOffSwitch と呼ばれる親クラスを作ることもできますが、とても 不自然です。 ラジオとコンピュータはこの親の特殊化ではありません。 この親は実際にはかなりおかしなものです。

This is where roles come in. It makes a lot of sense to create a HasOnOffSwitch role and apply it to both classes. This role would define a known API like providing turn_on() and turn_off() methods.

これはロールの出番です。 HasOnOffSwitch ロールを作って両方のクラスに適用することは とても合理的です。 このロールは turn_on()turn_off() メソッドを提供するような 既知の API を定義します。

Perl does not have any built-in way to express roles. In the past, people just bit the bullet and used multiple inheritance. Nowadays, there are several good choices on CPAN for using roles.

Perl にはロールを記述する組み込みの方法はありません。 以前は、人々は我慢して多重継承を使っていました。 最近は、ロールを使うためのいくつかの良い選択肢が CPAN にあります。

いつ OO を使うか

Object Orientation is not the best solution to every problem. In Perl Best Practices (copyright 2004, Published by O'Reilly Media, Inc.), Damian Conway provides a list of criteria to use when deciding if OO is the right fit for your problem:

オブジェクト指向は全ての問題に対する最良の解法というわけではありません。 Perl Best Practices (copyright 2004, Published by O'Reilly Media, Inc.) において、Damian Conway は OO が問題に正しく適応するかどうかを決定するときに 使う基準の一覧を提供しています:

  • The system being designed is large, or is likely to become large.

    設計しているシステムが大きいか、大きくなりそう。

  • The data can be aggregated into obvious structures, especially if there's a large amount of data in each aggregate.

    データが明らかな構造に集合できる; 特にそれぞれの集合が大量のデータを持つ。

  • The various types of data aggregate form a natural hierarchy that facilitates the use of inheritance and polymorphism.

    様々な型のデータ集合が、継承と多態性を使うことが容易な自然な階層を形成する。

  • You have a piece of data on which many different operations are applied.

    多くの異なった操作を適用するデータがある。

  • You need to perform the same general operations on related types of data, but with slight variations depending on the specific type of data the operations are applied to.

    データの種類に関係する同じ一般的な操作をする必要があるが、操作を適用する データの特定の種類に依存して少しずつ変化がある。

  • It's likely you'll have to add new data types later.

    後で新しいデータ型を追加する必要がありそう。

  • The typical interactions between pieces of data are best represented by operators.

    データ間の典型的な相互作用は演算子によって最もよく表現される。

  • The implementation of individual components of the system is likely to change over time.

    システムの独立した要素の実装が時間につれて変化しそう。

  • The system design is already object-oriented.

    システムの設計が既にオブジェクト指向である。

  • Large numbers of other programmers will be using your code modules.

    多くのプログラマがこのコードモジュールを使う。

Perl の OO システム

As we mentioned before, Perl's built-in OO system is very minimal, but also quite flexible. Over the years, many people have developed systems which build on top of Perl's built-in system to provide more features and convenience.

前述したように、Perl の組み込みの OO システムは非常に最小限ですが、 一方とても柔軟です。 年を重ねるにつれて、多くの人々がより多くの機能と利便性を提供するために Perl の組み込みのシステムの上に構築されたシステムを開発しました。

We strongly recommend that you use one of these systems. Even the most minimal of them eliminates a lot of repetitive boilerplate. There's really no good reason to write your classes from scratch in Perl.

私たちはこれらのシステムの一つを使うことを強く勧めます。 それらの中の最小限のものでも多くの繰り返される定型文を排除できます。 Perl でクラスを一から書く本当にいい理由というものはありません。

If you are interested in the guts underlying these systems, check out perlobj.

これらのシステムの基礎となる内部に興味があるなら、 perlobj を 調べてください。

Moose

Moose bills itself as a "postmodern object system for Perl 5". Don't be scared, the "postmodern" label is a callback to Larry's description of Perl as "the first postmodern computer language".

Moose は自分自身を「Perl 5 のためのポストモダンオブジェクトシステム」と 宣伝しています。 怖がらなくても大丈夫です; 「ポストモダン」というのはラリーが Perl のことを 「最初のポストモダンコンピュータ言語」と説明したことにちなんでいます。

Moose provides a complete, modern OO system. Its biggest influence is the Common Lisp Object System, but it also borrows ideas from Smalltalk and several other languages. Moose was created by Stevan Little, and draws heavily from his work on the Perl 6 OO design.

Moose は完全でモダンな OO システムを提供します。 その最大の影響元は Common Lisp Object System ですが、Smalltalk およびその他の いくつかの言語からもアイデアを借りています。 Moose は Stevan Little によって作成され、彼の Perl 6 OO 設計に関する 作業から多くを引いています。

Here is our File class using Moose:

以下は Moose を使った File クラスです:

  package File;
  use Moose;

  has path          => ( is => 'ro' );
  has content       => ( is => 'ro' );
  has last_mod_time => ( is => 'ro' );

  sub print_info {
      my $self = shift;

      print "This file is at ", $self->path, "\n";
  }

Moose provides a number of features:

Moose は多くの機能を提供します:

  • Declarative sugar

    (構文糖)

    Moose provides a layer of declarative "sugar" for defining classes. That sugar is just a set of exported functions that make declaring how your class works simpler and more palatable. This lets you describe what your class is, rather than having to tell Perl how to implement your class.

    Moose はクラスを定義するために、宣言的な「糖」の層を提供します。 この糖は、クラスがより簡単に、使いやすくなるようにするための単に エクスポートされた関数の集合です。 これは Perl が どのように クラスを実装するのかを教えるように するのではなく、クラスが 何を するかを表現するようにします。

    The has() subroutine declares an attribute, and Moose automatically creates accessors for these attributes. It also takes care of creating a new() method for you. This constructor knows about the attributes you declared, so you can set them when creating a new File.

    has() サブルーチンは属性を定義し、Moose は自動的にそれらの属性のための アクセサを作成します。 また、new() メソッドの面倒も見ます。 このコンストラクタは宣言された属性について知っているので、 新しい File を作成するときにそれを設定できます。

  • Roles built-in

    (組み込みのロール)

    Moose lets you define roles the same way you define classes:

    Moose はクラスを定義するのと同じようにロールを定義できます:

      package HasOnOffSwitch;
      use Moose::Role;
    
      has is_on => (
          is  => 'rw',
          isa => 'Bool',
      );
    
      sub turn_on {
          my $self = shift;
          $self->is_on(1);
      }
    
      sub turn_off {
          my $self = shift;
          $self->is_on(0);
      }
  • A miniature type system

    (小型の型システム)

    In the example above, you can see that we passed isa => 'Bool' to has() when creating our is_on attribute. This tells Moose that this attribute must be a boolean value. If we try to set it to an invalid value, our code will throw an error.

    前述の例では、is_on 属性を作成するときに has()isa => 'Bool' を渡します。 これは Moose に、この属性は真偽値でなければならないということを示します。 これに不正な値を設定しようとすると、エラーを投げます。

  • Full introspection and manipulation

    (完全なイントロスペクションと操作)

    Perl's built-in introspection features are fairly minimal. Moose builds on top of them and creates a full introspection layer for your classes. This lets you ask questions like "what methods does the File class implement?" It also lets you modify your classes programmatically.

    Perl の組み込みのイントロスペクション機能はかなり最低限です。 Moose はこれらの上に構築され、クラスのための完全なイントロスペクション 層を作成します。 これにより、「File クラスに実装されているメソッドは何?」といった問い合わせが できます。 また、クラスをプログラムで修正できます。

  • Self-hosted and extensible

    (セルフホスティングと拡張性)

    Moose describes itself using its own introspection API. Besides being a cool trick, this means that you can extend Moose using Moose itself.

    Moose は自分自身を自身のイントロスペクション API を使って記述しています。 かっこいい技という以外に、これは Moose 自身を使って Moose を 拡張できるということです。

  • Rich ecosystem

    (豊かなエコシステム)

    There is a rich ecosystem of Moose extensions on CPAN under the MooseX namespace. In addition, many modules on CPAN already use Moose, providing you with lots of examples to learn from.

    CPAN の MooseX 名前空間に、Moose 拡張の豊かなエコシステムがあります。 さらに、CPAN の多くのモジュールは既に Moose を使っていて、そこから学べる 多くの例を提供しています。

  • Many more features

    (さらに多くの機能)

    Moose is a very powerful tool, and we can't cover all of its features here. We encourage you to learn more by reading the Moose documentation, starting with Moose::Manual.

    Moose はとても強力なツールで、その機能の全てについてここで触れることは できません。 さらに学ぶために、Moose の文書を Moose::Manual から 読むことを勧めます。

Of course, Moose isn't perfect.

もちろん、Moose は完璧ではありません。

Moose can make your code slower to load. Moose itself is not small, and it does a lot of code generation when you define your class. This code generation means that your runtime code is as fast as it can be, but you pay for this when your modules are first loaded.

Moose によってコードの読み込みが遅くなることがあります。 Moose 自身が小さくなく、またクラスを定義するときに 大量 の コードを生成します。 このコード生成は、実行時コードは可能な限り高速であることを意味しますが、 このためにモジュールが最初に読み込まれるときにコストを支払うことになります。

This load time hit can be a problem when startup speed is important, such as with a command-line script or a "plain vanilla" CGI script that must be loaded each time it is executed.

この読み込み時間は、実行時に毎回読み込みしなければならない コマンドラインスクリプトや「何の変哲もない」CGIスクリプトのように、 起動速度が重要な場合には問題になり得ます。

Before you panic, know that many people do use Moose for command-line tools and other startup-sensitive code. We encourage you to try Moose out first before worrying about startup speed.

うろたえる前に、多くの人々がコマンドラインツールやその他の起動時間が重要な コードに Moose を使っていることを知ってください。 起動速度について気にする前にまず Moose を試してみることを勧めます。

Moose also has several dependencies on other modules. Most of these are small stand-alone modules, a number of which have been spun off from Moose. Moose itself, and some of its dependencies, require a compiler. If you need to install your software on a system without a compiler, or if having any dependencies is a problem, then Moose may not be right for you.

Moose はまた他のモジュールに対していくつかの依存があります。 それらのほとんどは小さいスタンドアロンのモジュールで、いくつかは Moose から切り離されたものです。 Moose 自身と、その依存のいくつかは、コンパイラを必要とします。 コンパイラのないシステムにインストールする必要があったり、どんな 依存があっても問題がある場合は、Moose は適切ではないかも知れません。

Moo

If you try Moose and find that one of these issues is preventing you from using Moose, we encourage you to consider Moo next. Moo implements a subset of Moose's functionality in a simpler package. For most features that it does implement, the end-user API is identical to Moose, meaning you can switch from Moo to Moose quite easily.

Moose を試してみて、これらの理由の一つが Moose を使うのを 妨げているなら、次に Moo を考慮するのを勧めます。 MooMoose の機能のサブセットをより単純なパッケージで実装しています。 実装されているほとんどの機能について、エンドユーザー API は Moose同一 です; つまり Moo から Moose にとても簡単に 切り替えられるということです。

Moo does not implement most of Moose's introspection API, so it's often faster when loading your modules. Additionally, none of its dependencies require XS, so it can be installed on machines without a compiler.

MooMoose のイントロスペクション API を実装しておらず、従って モジュールを読み込むときはしばしばより速いです。 さらに、XS が必要な依存はないので、コンパイラのないマシンでも インストールできます。

One of Moo's most compelling features is its interoperability with Moose. When someone tries to use Moose's introspection API on a Moo class or role, it is transparently inflated into a Moose class or role. This makes it easier to incorporate Moo-using code into a Moose code base and vice versa.

Moo の最も切実な機能は Moose との相互運用性です。 Moose のイントロスペクション API を Moo のクラスやロールで使おうと した場合、透過的に Moose のクラスやロールに変換されます。 これにより、Moo を使ったコードと Moose を使ったコードベースに組み込む、 またはその逆を行うことがより容易になります。

For example, a Moose class can subclass a Moo class using extends or consume a Moo role using with.

例えば、ある Moose のクラスは、extends を使った Moo のクラスの サブクラスになったり、with を使った Moo のロールを消費したりできます。

The Moose authors hope that one day Moo can be made obsolete by improving Moose enough, but for now it provides a worthwhile alternative to Moose.

Moose の作者は、いつの日か Moose が十分改良されることによって Moo が古いものになることを望んでいますが、今のところは Moose に対する 価値のある代替を提供します。

Class::Accessor

Class::Accessor is the polar opposite of Moose. It provides very few features, nor is it self-hosting.

Class::AccessorMoose の対極です。 非常に少ない機能しか提供しませんし、セルフホスティングでもありません。

It is, however, very simple, pure Perl, and it has no non-core dependencies. It also provides a "Moose-like" API on demand for the features it supports.

しかし、とても単純で、ピュア Perl で、非コア依存はありません。 また、対応している機能に対する「Moose 風」 API も提供しています。

Even though it doesn't do much, it is still preferable to writing your own classes from scratch.

多くのことはしませんが、それでもクラスを一から書くよりは望ましいです。

Here's our File class with Class::Accessor:

以下に Class::Accessor を使った File クラスを示します:

  package File;
  use Class::Accessor 'antlers';

  has path          => ( is => 'ro' );
  has content       => ( is => 'ro' );
  has last_mod_time => ( is => 'ro' );

  sub print_info {
      my $self = shift;

      print "This file is at ", $self->path, "\n";
  }

The antlers import flag tells Class::Accessor that you want to define your attributes using Moose-like syntax. The only parameter that you can pass to has is is. We recommend that you use this Moose-like syntax if you choose Class::Accessor since it means you will have a smoother upgrade path if you later decide to move to Moose.

antlers インポートフラグは、属性を Moose 風の文法で定義したいことを Class::Accessor に伝えます。 has に渡せる唯一の引数は is です。 Class::Accessor を選択した場合は、この Moose 風の文法を使うことを勧めます; なぜなら後に Moose に移行しようと決めたときによりスムーズに アップグレードできるからです。

Like Moose, Class::Accessor generates accessor methods and a constructor for your class.

Moose と同様、Class::Accessor はアクセサメソッドとコンストラクタを 生成します。

Class::Tiny

Finally, we have Class::Tiny. This module truly lives up to its name. It has an incredibly minimal API and absolutely no dependencies on any recent Perl. Still, we think it's a lot easier to use than writing your own OO code from scratch.

最後に、Class::Tiny があります。 このモジュールはまさにその名前通りです。 これは非常に最小限の API のみを持ち、最近の Perl では全く依存はありません。 それでも、一から独自の OO コードを書くよりも遙かに簡単に使えます。

Here's our File class once more:

以下に File クラスをもう一度示します:

  package File;
  use Class::Tiny qw( path content last_mod_time );

  sub print_info {
      my $self = shift;

      print "This file is at ", $self->path, "\n";
  }

That's it!

これだけです!

With Class::Tiny, all accessors are read-write. It generates a constructor for you, as well as the accessors you define.

Class::Tiny では、全てのアクセサは読み書き可能です。 コンストラクタと、定義したアクセサを生成します。

You can also use Class::Tiny::Antlers for Moose-like syntax.

Moose 風の文法の Class::Tiny::Antlers も使えます。

Role::Tiny

As we mentioned before, roles provide an alternative to inheritance, but Perl does not have any built-in role support. If you choose to use Moose, it comes with a full-fledged role implementation. However, if you use one of our other recommended OO modules, you can still use roles with Role::Tiny

前述したように、ロールは継承の代替策を提供しますが、Perl には組み込みの ロール対応はありません。 Moose を使うことを選んだ場合、完全なロール実装が同梱されています。 しかし、その他の推奨 OO モジュールを使う場合、Role::Tiny で ロールを使えます。

Role::Tiny provides some of the same features as Moose's role system, but in a much smaller package. Most notably, it doesn't support any sort of attribute declaration, so you have to do that by hand. Still, it's useful, and works well with Class::Accessor and Class::Tiny

Role::Tiny は Moose のロールシステムと同じような機能を提供しますが、 パッケージは遙かに小さいです。 特に、属性宣言には対応していないので、手動で行う必要があります。 それでも、これは有用で、Class::Accessor および Class::Tiny と うまく動作します。

OO システムの要約

Here's a brief recap of the options we covered:

以下はここで取り上げた選択肢の簡潔なまとめです:

  • Moose

    Moose is the maximal option. It has a lot of features, a big ecosystem, and a thriving user base. We also covered Moo briefly. Moo is Moose lite, and a reasonable alternative when Moose doesn't work for your application.

    Moose は最大限のオプションです。 多くの機能、大きなエコシステム、繁栄しているユーザーベースがあります。 また、Moo も簡単に取り上げました。 MooMoose の簡略版で、Moose があなたのアプリケーションで 動作しないときの妥当な代替案です。

  • Class::Accessor

    Class::Accessor does a lot less than Moose, and is a nice alternative if you find Moose overwhelming. It's been around a long time and is well battle-tested. It also has a minimal Moose compatibility mode which makes moving from Class::Accessor to Moose easy.

    Class::Accessor がすることは Moose よりもとても少なく、Moose が おおげさな時にはよい選択肢です。 長い間存在し、よくテストされています。 Class::Accessor から Moose への以降を容易にするための最小限の Moose 互換モードもあります。

  • Class::Tiny

    Class::Tiny is the absolute minimal option. It has no dependencies, and almost no syntax to learn. It's a good option for a super minimal environment and for throwing something together quickly without having to worry about details.

    Class::Tiny は明らかに最小限のオプションです。 依存はなく、学ぶ必要のある文法もほとんどありません。 超最小限環境の場合や詳細について心配することなく素早く何かを作るときには よいオプションです。

  • Role::Tiny

    Use Role::Tiny with Class::Accessor or Class::Tiny if you find yourself considering multiple inheritance. If you go with Moose, it comes with its own role implementation.

    多重継承について考えているなら Class::Accessor または Class::Tiny と 共に Role::Tiny を使ってください。 Moose を使っているなら、独自のロール実装が同梱されています。

その他の OO システム

There are literally dozens of other OO-related modules on CPAN besides those covered here, and you're likely to run across one or more of them if you work with other people's code.

ここで扱ったものの他に、CPAN には文字通り数十のその他の OO 関連の モジュールがあり、他の人のコードを動かすときにはおそらく それらのいくつかを使っているでしょう。

In addition, plenty of code in the wild does all of its OO "by hand", using just the Perl built-in OO features. If you need to maintain such code, you should read perlobj to understand exactly how Perl's built-in OO works.

さらに、世の中の多くのコードは全ての OO を「手動で」、単に Perl 組み込みの OO 機能を使って行っています。 もしそのようなコードを保守する必要があるなら、Perl の組み込みの OO が どのように動作するのかを正確に理解するためにperlobj を読むべきです。

まとめ

As we said before, Perl's minimal OO system has led to a profusion of OO systems on CPAN. While you can still drop down to the bare metal and write your classes by hand, there's really no reason to do that with modern Perl.

既に述べたように、Perl の最小限の OO システムは CPAN での豊富な OO システムを 生み出しました。 今でもこの地金まで降りていってクラスを手で書くこともできる一方、 モダン Perl においてそうする理由は本当はありません。

For small systems, Class::Tiny and Class::Accessor both provide minimal object systems that take care of basic boilerplate for you.

小さいシステムなら、Class::TinyClass::Accessor の両方は 基本的な定型文の面倒を見る最小限のオブジェクトシステムを提供します。

For bigger projects, Moose provides a rich set of features that will let you focus on implementing your business logic. Moo provides a nice alternative to Moose when you want a lot of features but need faster compile time or to avoid XS.

より大きいプロジェクトなら、Moose はあなたがビジネスロジックの実装に 集中できるような豊富な機能セットを提供します。 多くの機能が必要だけれどもより早いコンパイル時間が必要だったり XS を避けたい場合、MooMoose のよい代替案です。

We encourage you to play with and evaluate Moose, Moo, Class::Accessor, and Class::Tiny to see which OO system is right for you.

どの OO システムが適しているかを見るために、Moose, Moo, Class::Accessor, Class::Tiny を試して評価することをお勧めします。