Object::Simple::Guide::Ja - Object::Simpleの日本語ガイド
オブジェクト指向プログラミングを行いクラスを作成するとき のひとつのよい習慣は、メソッドのみによってオブジェクトにアクセス することです。オブジェクトにはデータを格納していますが、 この値は属性と呼ばれます。 属性を取得したり、設定したりする場合にも そのためのメソッドを定義するのがよいでしょう。 このようなメソッドはアクセッサメソッドと呼ばれます。 このガイドではアクセッサと呼ぶことにします。
アクセッサの定義は通常は次のようになります。
package Point; sub x { my $self = shift; if (@_) { $self->{x} = $_[0]; } return $self->{x}; }
アクセッサは単純で単に属性を設定し、取得するメソッドです。 オブジェクトは通常たくさんの属性を持ちますから、 このようなメソッドをたくさん定義するのは大変です。 簡潔に記述したいと思うことでしょう。
Object::Simpleはアクセッサを生成するためのメソッドを 提供するクラスです。次のような記述でアクセッサを生成することができます。
__PACKAGE__->attr('x');
この記述を行うだけでアクセッサが生成されます。
Perlのモジュールの中にはこのようなアクセッサを生成するための メソッドがたくさんありますが、Object::Simpleの特徴は 何ですか。
もっとも一般的に利用されているClass::Accessor::Fastに 対する利点は、アクセッサのデフォルト値を定義できることです。
__PACAKGE__->attr(x => 0);
またObject::Simpleはコンストラクタも提供しますが、 コンストラクタがハッシュとハッシュのリファレンスの両方 を受け取ることができることです。
my $point = Point->new(x => 1, y => 1); my $point = Point->new({x => 1, y => 1});
Mooseなどの高度なクラスビルダーに対する利点はなんですか。 それは、きわめて重複を少なくアクセッサを定義できることです。 attrを一回呼ぶだけで、すべてのアクセッサを定義することもできます。
__PACKAGE__->attr( [qw/foo bar baz/], some => 1, other => sub { 5 } );
またアクセッサに付属する機能として、デフォルト値の機能に限定することで、 ソースコードがわかりやすく、直感的になるということです。 デフォルト値が定義できさえすれば、美しく高度なモジュールを 記述できるということはMojoliciousという高度なWebアプリケーション フレームワークが、この機能だけを使って構成されている ということからもわかります。
Object::Simpelはプログラマが使いやすいように設計されています。 Object::Simpelを使ってクラスをきれいに書きたいと 思われた方は、以下の詳しい解説を読まれてみてください。
最初に、Object::Simpleのメソッドを利用するために、 Object::Simpleを継承したクラスを作成します
package SomeClass; use base 'Object::Simple';
Object::Simpleはnew()メソッドを持っています。 これはコンストラクタで、 ハッシュかハッシュのリファレンスを受け取ることができます。
new()
my $obj = SomeClass->new; my $obj = SomeClass->new(foo => 1, bar => 2); my $obj = SomeClass->new({foo => 1, bar => 2});
attr()メソッドによって、アクセッサを生成することができます。
attr()
__PACKAGE__->attr('foo');
アクセッサを使って値を設定したり取得することができます。
# Set the value $obj->foo(1); # Get the value my $foo = $obj->foo;
アクセッサのためのデフォルト値を指定することもできます。
__PACKAGE__->attr(foo => 1);
fooの値が存在しないで、fooメソッドが呼び出されると、 デフォルト値を取得することができます。
foo
my $default_value = $obj->foo;
もしリファレンスやオブジェクトをデフォルト値として指定したい場合は デフォルト値を返却するサブルーチンのリファレンスである必要があります。 これはデフォルト値を他のオブジェクトと共有しないために必要です。
__PACKAGE__->attr(foo => sub { [] }); __PACKAGE__->attr(foo => sub { {} }); __PACKAGE__->attr(foo => sub { SomeClass->new });
アクセッサを一度に生成することもできます。
__PACKAGE__->attr([qw/foo bar baz/]); __PACKAGE__->attr([qw/foo bar baz/] => 0);
さらに簡単にアクセッサを定義することもできます。
__PACKAGE__->attr( some => 1, other => sub { 5 } );
引数が奇数個の場合には、一つ目の引数に渡された値については、 デフォルト値を持たないアクセッサとして解釈します。
これが一番簡単なアクセッサの生成方法です。
サンプル:
Object::Simpleをよく理解するためにひとつのサンプルを見せます。
Pointクラスは、xとyというふたつの属性と、 xとyの値を0にクリアする<clear>というメソッドを持ちます。
Point
x
y
package Point; use strict; use warnings; use base 'Object::Simple'; __PACKAGE__->attr(x => 0); __PACKAGE__->attr(y => 0); sub clear { my $self = shift; $self->x(0); $self->y(0); }
Point3Dクラスは、Pointクラスを継承します。 このクラスはxとyという属性に加えて、zという属性 を持っています。 clear()メソッドはxとyとzの値をクリアするために オーバーライドされています。
Point3D
z
clear()
package Point3D; use strict; use warnings; use base 'Point'; __PACKAGE__->attr(z => 0); sub clear { my $self = shift; $self->SUPER::clear(); $self->z(0); }
Object::Simpleをよく理解するために、 オブジェクト指向の概念を解説したいと思います。
オブジェクト指向の一つ目の概念は「継承」です。 「継承」は「もしクラスQがクラスPを継承していたら、 クラスQはクラスPのすべてのメソッドを呼び出すことができる」 ということを意味します。
+---+ | P | Base class +---+ having method1() and method2() | +---+ | Q | Sub class +---+ having method3()
クラスQはクラスPを継承しているので、 クラスQはクラスQのメソッドに加えて、クラスPのすべてのメソッド を呼び出すことができます。 言い換えれば、クラスQは method1(), method2()とmethod3() を呼び出すことができます。
method1()
method2()
method3()
継承を行うには、baseモジュールを使用します。
package P; sub method1 { ... } sub method2 { ... } package Q; use base 'P'; sub method3 { ... }
Perlはオブジェクト指向プログラミングを助ける 便利な関数とメソッドを持っています。
オブジェクトがどのクラスに属しているかを知るには、 ref()関数を使用します。
ref()
my $class = ref $obj;
オブジェクトが特定のクラスを継承しているかどうかを調べるには、 isa()メソッドを使用します。
isa()
$obj->isa('SomeClass');
オブジェクト(あるいはクラス)が特定のメソッドを呼び出す ことができるかどうかを知るには、 can()メソッドを使用します。
can()
SomeClass->can('method1'); $obj->can('method1');
オブジェクト指向プログラミングのふたつ目の概念は カプセル化です。 「カプセル化」は「内部的にデータに直接アクセスしてはいけない」 ということを意味します。 ドキュメントに記述された公開されたメソッドを使用しなければ なりません。 このルールを守ることによって、すべてのことがシンプルになります。
このルールを守るためには 値を取得や設定を行うためのアクセッサを生成する 必要があります。
my $value = $obj->foo; $obj->foo(1);
直接データにアクセスするのは良くない習慣です。
my $value = $obj->{foo}; # Bad manner! $obj->{foo} = 1; # Bad manner!
オブジェクト指向プログラミングの三つ目の概念は 「ポリモーフィズム」です。 「ポリモーフィズム」は、 「オーバーロード」と「オーバーライド」のふたつの概念に 分割されます。
Perlプログラマはオーバーロードを気にする必要はありません。 Perlは動的な言語なので、 サブルーチンはどのような値でも受け取ることができます。 オーバーロードはC++やJavaなどの 静的な型を持つ言語にとって価値があります。
「オーバーライド」は「サブクラスにおいて、基底クラスのメソッドを 変更することができる」ということを意味します。
package P; sub method1 { return 1 } package Q; use base 'P'; sub method1 { return 2 }
クラスPのmethod1()は1という値を返却します。 クラスQのmethod1()は2という値を返却します。 つまり、クラスQにおいて、method1()はオーバーライド されたということです。
my $obj_a = P->new; $obj_p->method1; # Return value is 1 my $obj_b = Q->new; $obj_q->method1; # Return value is 2
もし基底クラスのメソッドをサブクラスから呼び出したい場合は SUPER擬似クラスを使用します。
package Q; sub method1 { my $self = shift; my $value = $self->SUPER::method1(); # return value is 1 return 2 + $value; }
これらの三つの概念だけを理解するならば、 十分強力なオブジェクト指向プログラムができ、 ソースコードは他の言語のユーザから見ても 読みやすいものになるでしょう。
new()メソッドは必要ならばオーバーライドすることができます。
オブジェクトの初期化。
sub new { my $self = shift->SUPER::new(@_); # Initialization return $self; }
new()の引数の変更。
sub new { my $self = shift; $self->SUPER::new(x => $_[0], y => $_[1]); return $self; } C<new()>メソッドをオーバーライドすることによって、 C<new()>に配列を渡すことができるようになりました。 my $point = Point->new(4, 5);
Object::Simpleはユーザビリティにも注意を払っています。 もし間違った数の引数がnew()メソッドに渡されるならば、 例外が発生します。
my $obj = SomeClass->new(1); # Exception!
アクセッサにおいても同じです。
$obj->foo(a => 1); # Execption!
Object::Simpleのメソッドをインポートすることができます。 これは多重継承を行いたくない場合に便利です。
package SomeClass; use Object::Simple qw/new attr/; __PACKAGE__->attr('foo');
new()はクラスにインポートされるのであって、 基底クラスから継承したわけではないので、 new()メソッドをオーバーライドすることはできない ということに注意してください。
アクセッサは、値を設定するために呼ばれたときに、 自分自分のオブジェクトを返却するので、メソッドチェーンを 行うことができます。
$obj->foo(1)->bar(4)->baz(6);
To install Object::Simple, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Object::Simple
CPAN shell
perl -MCPAN -e shell install Object::Simple
For more information on module installation, please visit the detailed CPAN module installation guide.