PERLでのオブジェクト指向プログラミング

PerlおよびPerlの匿名配列とハッシュでの参照についてはすでに検討しました。Perlのオブジェクト指向の概念は、参照と匿名の配列とハッシュに非常に基づいています。オブジェクト指向Perlの基本的な概念を学び始めましょう。

オブジェクトの基本

Perlがオブジェクトを処理する方法の観点から説明される、3つの主要な用語があります。用語は、オブジェクト、クラス、およびメソッドです。

  • アン objectPerl内では、それがどのクラスに属しているかを知っているデータ型への参照にすぎません。オブジェクトは、参照としてスカラー変数に格納されます。スカラーにはオブジェクトへの参照のみが含まれるため、同じスカラーが異なるクラスの異なるオブジェクトを保持できます。

  • A class Perl内には、オブジェクトの作成と操作に必要な対応するメソッドを含むパッケージがあります。

  • A methodPerl内には、パッケージで定義されたサブルーチンがあります。メソッドの最初の引数は、メソッドが現在のオブジェクトまたはクラスのどちらに影響するかに応じて、オブジェクト参照またはパッケージ名です。

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

これで、Employeeクラスには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);
   }
}

デストラクタとガベージコレクション

以前にオブジェクト指向プログラミングを使用してプログラミングしたことがある場合は、を作成する必要があることに気付くでしょう。 destructorオブジェクトの使用が終了したときに、オブジェクトに割り当てられたメモリを解放します。オブジェクトがスコープから外れるとすぐに、Perlはこれを自動的に行います。

ファイルを閉じるか、追加の処理を行う必要があるデストラクタを実装する場合は、次のような特別なメソッドを定義する必要があります。 DESTROY。このメソッドは、Perlが割り当てられたメモリを解放する直前にオブジェクトに対して呼び出されます。他のすべての点で、DESTROYメソッドは他のメソッドとまったく同じであり、このメソッド内に必要なロジックを実装できます。

デストラクタメソッドは、DESTROYという名前のメンバー関数(サブルーチン)であり、次の場合に自動的に呼び出されます。

  • オブジェクト参照の変数がスコープ外になったとき。
  • オブジェクト参照の変数が定義されていない場合。
  • スクリプトが終了したとき
  • Perlインタプリタが終了したとき

たとえば、次のメソッドDESTROYをクラスに配置するだけです。

package MyClass;
...
sub DESTROY {
   print "MyClass::DESTROY called\n";
}

オブジェクト指向のPerlの例

これは、Perlのオブジェクト指向の概念を理解するのに役立つもう1つの良い例です。このソースコードを任意の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