Perl-object-oriented
PERLでのオブジェクト指向プログラミング
PerlおよびPerlの匿名配列およびハッシュの参照については既に検討しています。 Perlのオブジェクト指向の概念は、参照と匿名配列およびハッシュに非常に基づいています。 オブジェクト指向Perlの基本概念の学習を始めましょう。
オブジェクトの基本
Perlがオブジェクトを処理する方法の観点から説明される3つの主要な用語があります。 用語は、オブジェクト、クラス、およびメソッドです。
- Perl内の*オブジェクト*は、それが属するクラスを知っているデータ型への単なる参照です。 オブジェクトは、参照としてスカラー変数に格納されます。 スカラーにはオブジェクトへの参照のみが含まれるため、同じスカラーは異なるクラスの異なるオブジェクトを保持できます。
- Perl内の class は、オブジェクトの作成と操作に必要な対応するメソッドを含むパッケージです。
- Perl内の method は、パッケージで定義されたサブルーチンです。 メソッドの最初の引数は、メソッドが現在のオブジェクトまたはクラスに影響するかどうかに応じて、オブジェクト参照またはパッケージ名です。
Perlは* bless()*関数を提供します。これは、最終的にオブジェクトになる参照を返すために使用されます。
クラスを定義する
Perlでクラスを定義するのは非常に簡単です。 クラスは、最も単純な形式のPerlパッケージに対応しています。 Perlでクラスを作成するには、まずパッケージをビルドします。
パッケージは、ユーザー定義の変数とサブルーチンの自己完結型のユニットであり、繰り返し再利用できます。
Perlパッケージは、サブルーチンと変数を他のパッケージと競合しないように保つPerlプログラム内に別の名前空間を提供します。
PerlでPersonという名前のクラスを宣言するには、次のようにします-
package Person;
パッケージ定義の範囲は、ファイルの最後まで、または別のパッケージキーワードが見つかるまで続きます。
オブジェクトの作成と使用
クラス(オブジェクト)のインスタンスを作成するには、オブジェクトコンストラクターが必要です。 このコンストラクタは、パッケージ内で定義されたメソッドです。 ほとんどのプログラマーはこのオブジェクトコンストラクターメソッドにnewという名前を付けることを選択しますが、Perlでは任意の名前を使用できます。
Perlでは、あらゆる種類のPerl変数をオブジェクトとして使用できます。 ほとんどのPerlプログラマは、配列またはハッシュへの参照を選択します。
Perlハッシュ参照を使用してPersonクラスのコンストラクターを作成しましょう。 オブジェクトを作成するときは、コンストラクターを提供する必要があります。コンストラクターは、オブジェクト参照を返すパッケージ内のサブルーチンです。 オブジェクト参照は、パッケージのクラスへの参照を祝福することによって作成されます。 たとえば-
package Person;
sub new {
my $class = shift;
my $self = {
_firstName => shift,
_lastName => shift,
_ssn => shift,
};
# Print all the values just for clarification.
print "First Name is $self->{_firstName}\n";
print "Last Name is $self->{_lastName}\n";
print "SSN is $self->{_ssn}\n";
bless $self, $class;
return $self;
}
次に、オブジェクトの作成方法を見てみましょう。
$object = new Person( "Mohammad", "Saleem", 23234345);
クラス変数に値を割り当てたくない場合は、コンストラクターで単純なハッシュを使用できます。 たとえば-
package Person;
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
return $self;
}
メソッドの定義
他のオブジェクト指向言語には、データのセキュリティという概念があり、プログラマがオブジェクトデータを直接変更するのを防ぎ、オブジェクトデータを変更するためのアクセサメソッドを提供します。 Perlにはプライベート変数はありませんが、ヘルパーメソッドの概念を使用してオブジェクトデータを操作できます。
人の名を取得するヘルパーメソッドを定義しましょう-
sub getFirstName {
return $self->{_firstName};
}
人の名を設定する別のヘルパー機能-
sub setFirstName {
my ( $self, $firstName ) = @_;
$self->{_firstName} = $firstName if defined($firstName);
return $self->{_firstName};
}
次に、完全な例を見てみましょう。Personパッケージとヘルパー関数をPerson.pmファイルに保存します。
#!/usr/bin/perl
package Person;
sub new {
my $class = shift;
my $self = {
_firstName => shift,
_lastName => shift,
_ssn => shift,
};
# Print all the values just for clarification.
print "First Name is $self->{_firstName}\n";
print "Last Name is $self->{_lastName}\n";
print "SSN is $self->{_ssn}\n";
bless $self, $class;
return $self;
}
sub setFirstName {
my ( $self, $firstName ) = @_;
$self->{_firstName} = $firstName if defined($firstName);
return $self->{_firstName};
}
sub getFirstName {
my( $self ) = @_;
return $self->{_firstName};
}
1;
次のようにemployee.plファイルのPersonオブジェクトを利用しましょう-
#!/usr/bin/perl
use Person;
$object = new Person( "Mohammad", "Saleem", 23234345);
# Get first name which is set using constructor.
$firstName = $object->getFirstName();
print "Before Setting First Name is : $firstName\n";
# Now Set first name using helper function.
$object->setFirstName( "Mohd." );
# Now get first name set by helper function.
$firstName = $object->getFirstName();
print "Before Setting First Name is : $firstName\n";
上記のプログラムを実行すると、次の結果が生成されます-
First Name is Mohammad
Last Name is Saleem
SSN is 23234345
Before Setting First Name is : Mohammad
Before Setting First Name is : Mohd.
継承
オブジェクト指向プログラミングには、継承と呼ばれる非常に優れた便利な概念があります。 継承とは、親クラスのプロパティとメソッドが子クラスで利用できることを意味します。 したがって、同じコードを何度も書く必要はなく、親クラスを継承するだけです。
たとえば、Personを継承するEmployeeクラスを作成できます。 これは、従業員が個人であるため、「isa」関係と呼ばれます。 Perlには、これを支援する特別な変数@ISAがあります。 @ISAは(メソッド)継承を管理します。
以下は、継承を使用する際に考慮すべき重要な点です-
- Perlは、指定されたオブジェクトのクラスで、指定されたメソッドまたは属性、つまり変数を検索します。
- Perlは、オブジェクトクラスの@ISA配列で定義されたクラスを検索します。
- 手順1または2でメソッドが見つからない場合、@ ISAツリーで見つかった場合、PerlはAUTOLOADサブルーチンを使用します。
- それでも一致するメソッドが見つからない場合、Perlは標準Perlライブラリの一部として提供されるUNIVERSALクラス(パッケージ)内でメソッドを検索します。
- メソッドがまだ見つからない場合、Perlは放棄してランタイム例外を発生させます。
したがって、Personクラスからメソッドと属性を継承する新しいEmployeeクラスを作成するには、次のようにコーディングするだけです。このコードをEmployee.pmに保持します。
#!/usr/bin/perl
package Employee;
use Person;
use strict;
our @ISA = qw(Person); # inherits from Person
これで、従業員クラスにはPersonクラスから継承されたすべてのメソッドと属性があり、次のように使用できます。main.plファイルを使用してテストします-
#!/usr/bin/perl
use Employee;
$object = new Employee( "Mohammad", "Saleem", 23234345);
# Get first name which is set using constructor.
$firstName = $object->getFirstName();
print "Before Setting First Name is : $firstName\n";
# Now Set first name using helper function.
$object->setFirstName( "Mohd." );
# Now get first name set by helper function.
$firstName = $object->getFirstName();
print "After Setting First Name is : $firstName\n";
上記のプログラムを実行すると、次の結果が生成されます-
First Name is Mohammad
Last Name is Saleem
SSN is 23234345
Before Setting First Name is : Mohammad
Before Setting First Name is : Mohd.
メソッドのオーバーライド
子クラスEmployeeは、親クラスPersonからすべてのメソッドを継承します。 ただし、子クラスでこれらのメソッドをオーバーライドする場合は、独自の実装を提供することでそれを行うことができます。 追加の関数を子クラスに追加するか、親クラスの既存のメソッドの機能を追加または変更できます。 次のように実行できます。Employee.pmファイルを変更します。
#!/usr/bin/perl
package Employee;
use Person;
use strict;
our @ISA = qw(Person); # inherits from Person
# Override constructor
sub new {
my ($class) = @_;
# Call the constructor of the parent class, Person.
my $self = $class->SUPER::new( $_[1], $_[2], $_[3] );
# Add few more attributes
$self->{_id} = undef;
$self->{_title} = undef;
bless $self, $class;
return $self;
}
# Override helper function
sub getFirstName {
my( $self ) = @_;
# This is child class function.
print "This is child class helper function\n";
return $self->{_firstName};
}
# Add more methods
sub setLastName{
my ( $self, $lastName ) = @_;
$self->{_lastName} = $lastName if defined($lastName);
return $self->{_lastName};
}
sub getLastName {
my( $self ) = @_;
return $self->{_lastName};
}
1;
ここで、再びmain.plファイルでEmployeeオブジェクトを使用して実行してみましょう。
#!/usr/bin/perl
use Employee;
$object = new Employee( "Mohammad", "Saleem", 23234345);
# Get first name which is set using constructor.
$firstName = $object->getFirstName();
print "Before Setting First Name is : $firstName\n";
# Now Set first name using helper function.
$object->setFirstName( "Mohd." );
# Now get first name set by helper function.
$firstName = $object->getFirstName();
print "After Setting First Name is : $firstName\n";
上記のプログラムを実行すると、次の結果が生成されます-
First Name is Mohammad
Last Name is Saleem
SSN is 23234345
This is child class helper function
Before Setting First Name is : Mohammad
This is child class helper function
After Setting First Name is : Mohd.
デフォルトのオートローディング
Perlには、他のプログラミング言語にはない機能、デフォルトのサブルーチンがあります。 つまり、* AUTOLOAD()*という関数を定義すると、未定義のサブルーチンを呼び出すと、AUTOLOAD()関数が自動的に呼び出されます。 不足しているサブルーチンの名前には、このサブルーチン内で$ AUTOLOADとしてアクセスできます。
デフォルトの自動ロード機能は、エラー処理に非常に役立ちます。 AUTOLOADを実装する例を次に示します。この関数は独自の方法で実装できます。
sub AUTOLOAD {
my $self = shift;
my $type = ref ($self) || croak "$self is not an object";
my $field = $AUTOLOAD;
$field =~ s/.*://;
unless (exists $self->{$field}) {
croak "$field does not exist in object/class $type";
}
if (@_) {
return $self->($name) = shift;
} else {
return $self->($name);
}
}
デストラクタとガベージコレクション
以前にオブジェクト指向プログラミングを使用してプログラミングしたことがある場合は、オブジェクトの使用が終了したときにオブジェクトに割り当てられたメモリを解放するために*デストラクタ*を作成する必要があることに気付くでしょう。 Perlは、オブジェクトがスコープから外れるとすぐにこれを自動的に行います。
ファイルを閉じたり、余分な処理を行うデストラクタを実装する場合は、 DESTROY という特別なメソッドを定義する必要があります。 このメソッドは、Perlがそれに割り当てられたメモリを解放する直前にオブジェクトで呼び出されます。 他のすべての点で、DESTROYメソッドは他のメソッドとまったく同じであり、このメソッド内に任意のロジックを実装できます。
デストラクタメソッドは、単にDESTROYという名前のメンバー関数(サブルーチン)であり、次の場合に自動的に呼び出されます-
- オブジェクト参照の変数が範囲外になるとき。
- オブジェクト参照の変数が未定義の場合。
- スクリプトが終了するとき
- Perlインタープリターが終了するとき
たとえば、次のメソッドDESTROYをクラスに単純に入れることができます-
package MyClass;
...
sub DESTROY {
print "MyClass::DESTROY called\n";
}
オブジェクト指向Perlの例
次に、Perlのオブジェクト指向の概念を理解するのに役立つ別の素晴らしい例を示します。 このソースコードを任意のperlファイルに入れて実行します。
#!/usr/bin/perl
# Following is the implementation of simple Class.
package MyClass;
sub new {
print "MyClass::new called\n";
my $type = shift; # The package/type name
my $self = {}; # Reference to empty hash
return bless $self, $type;
}
sub DESTROY {
print "MyClass::DESTROY called\n";
}
sub MyMethod {
print "MyClass::MyMethod called!\n";
}
# Following is the implemnetation of Inheritance.
package MySubClass;
@ISA = qw( MyClass );
sub new {
print "MySubClass::new called\n";
my $type = shift; # The package/type name
my $self = MyClass->new; # Reference to empty hash
return bless $self, $type;
}
sub DESTROY {
print "MySubClass::DESTROY called\n";
}
sub MyMethod {
my $self = shift;
$self->SUPER::MyMethod();
print " MySubClass::MyMethod called!\n";
}
# Here is the main program using above classes.
package main;
print "Invoke MyClass method\n";
$myObject = MyClass->new();
$myObject->MyMethod();
print "Invoke MySubClass method\n";
$myObject2 = MySubClass->new();
$myObject2->MyMethod();
print "Create a scoped object\n";
{
my $myObject2 = MyClass->new();
}
# Destructor is called automatically here
print "Create and undef an object\n";
$myObject3 = MyClass->new();
undef $myObject3;
print "Fall off the end of the script...\n";
# Remaining destructors are called automatically here
上記のプログラムを実行すると、次の結果が生成されます-
Invoke MyClass method
MyClass::new called
MyClass::MyMethod called!
Invoke MySubClass method
MySubClass::new called
MyClass::new called
MyClass::MyMethod called!
MySubClass::MyMethod called!
Create a scoped object
MyClass::new called
MyClass::DESTROY called
Create and undef an object
MyClass::new called
MyClass::DESTROY called
Fall off the end of the script...
MyClass::DESTROY called
MySubClass::DESTROY called