การเขียนโปรแกรมเชิงวัตถุใน PERL

เราได้ศึกษาการอ้างอิงในอาร์เรย์และแฮชแบบไม่ระบุตัวตนของ Perl และ Perl แล้ว แนวคิดเชิงวัตถุใน Perl นั้นขึ้นอยู่กับการอ้างอิงและอาร์เรย์และแฮชที่ไม่ระบุชื่อเป็นอย่างมาก เริ่มต้นเรียนรู้แนวคิดพื้นฐานของ Perl เชิงวัตถุ

พื้นฐานของวัตถุ

มีสามคำหลักที่อธิบายจากมุมมองของวิธีที่ Perl จัดการกับวัตถุ เงื่อนไขคือวัตถุคลาสและวิธีการ

  • อัน objectภายใน Perl เป็นเพียงการอ้างอิงถึงชนิดข้อมูลที่รู้ว่าเป็นของคลาสใด อ็อบเจ็กต์ถูกเก็บไว้เป็นข้อมูลอ้างอิงในตัวแปรสเกลาร์ เนื่องจากสเกลาร์มีเฉพาะการอ้างอิงถึงวัตถุสเกลาร์เดียวกันจึงสามารถเก็บวัตถุที่แตกต่างกันในคลาสต่างๆได้

  • class ภายใน Perl เป็นแพ็คเกจที่มีวิธีการที่เกี่ยวข้องซึ่งจำเป็นในการสร้างและจัดการวัตถุ

  • methodภายใน Perl เป็นรูทีนย่อยที่กำหนดด้วยแพ็กเกจ อาร์กิวเมนต์แรกของเมธอดคือการอ้างอิงอ็อบเจ็กต์หรือชื่อแพ็กเกจขึ้นอยู่กับว่าเมธอดมีผลต่ออ็อบเจ็กต์ปัจจุบันหรือคลาส

Perl ให้ bless() ฟังก์ชันซึ่งใช้เพื่อส่งคืนการอ้างอิงซึ่งท้ายที่สุดจะกลายเป็นวัตถุ

การกำหนดคลาส

การกำหนดคลาสใน Perl นั้นง่ายมาก คลาสจะสอดคล้องกับแพ็คเกจ Perl ในรูปแบบที่ง่ายที่สุด ในการสร้างคลาสใน Perl เราต้องสร้างแพ็คเกจก่อน

แพ็กเกจคือหน่วยที่มีอยู่ในตัวของตัวแปรและรูทีนย่อยที่ผู้ใช้กำหนดเองซึ่งสามารถใช้ซ้ำได้ซ้ำแล้วซ้ำเล่า

Perl Packages จัดเตรียมเนมสเปซแยกต่างหากภายในโปรแกรม Perl ซึ่งทำให้รูทีนย่อยและตัวแปรเป็นอิสระจากความขัดแย้งกับในแพ็กเกจอื่น ๆ

ในการประกาศคลาสชื่อบุคคลใน Perl เราทำ -

package Person;

ขอบเขตของนิยามแพ็กเกจจะขยายไปจนถึงจุดสิ้นสุดของไฟล์หรือจนกว่าจะพบคีย์เวิร์ดแพ็กเกจอื่น

การสร้างและใช้วัตถุ

ในการสร้างอินสแตนซ์ของคลาส (วัตถุ) เราจำเป็นต้องมีตัวสร้างวัตถุ ตัวสร้างนี้เป็นวิธีการที่กำหนดภายในแพ็คเกจ โปรแกรมเมอร์ส่วนใหญ่เลือกที่จะตั้งชื่อเมธอดตัวสร้างอ็อบเจ็กต์นี้ใหม่ แต่ใน Perl คุณสามารถใช้ชื่อใดก็ได้

คุณสามารถใช้ตัวแปร Perl ชนิดใดก็ได้เป็นวัตถุใน Perl โปรแกรมเมอร์ Perl ส่วนใหญ่เลือกการอ้างอิงถึงอาร์เรย์หรือแฮช

มาสร้างตัวสร้างของเราสำหรับคลาส Person ของเราโดยใช้การอ้างอิงแฮช 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;
}

ตอนนี้ให้เราดูวิธีการสร้างวัตถุ

$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};
}

ตอนนี้เรามาดูตัวอย่างที่สมบูรณ์: Keep Person package และ helper functions into Person.pm file.

#!/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;

ตอนนี้เรามาใช้ประโยชน์จากวัตถุบุคคลในไฟล์ staff.pl ดังนี้ -

#!/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.

มรดก

การเขียนโปรแกรมเชิงวัตถุมีแนวคิดที่ดีและมีประโยชน์ที่เรียกว่าการสืบทอด การสืบทอดหมายความว่าคุณสมบัติและวิธีการของคลาสพาเรนต์จะพร้อมใช้งานสำหรับคลาสย่อย ดังนั้นคุณไม่จำเป็นต้องเขียนโค้ดเดิมซ้ำแล้วซ้ำอีกคุณสามารถสืบทอดคลาสพาเรนต์ได้

ตัวอย่างเช่นเราสามารถมีคลาส Employee ซึ่งสืบทอดมาจาก Person สิ่งนี้เรียกว่าความสัมพันธ์แบบ "isa" เนื่องจากพนักงานเป็นบุคคล Perl มีตัวแปรพิเศษ @ISA เพื่อช่วยในเรื่องนี้ @ISA ควบคุมการสืบทอด (วิธีการ)

ต่อไปนี้เป็นประเด็นสำคัญที่ต้องพิจารณาในขณะที่ใช้มรดก -

  • Perl ค้นหาคลาสของอ็อบเจ็กต์ที่ระบุสำหรับเมธอดหรือแอ็ตทริบิวต์ที่กำหนดเช่นตัวแปร

  • Perl ค้นหาคลาสที่กำหนดไว้ในอาร์เรย์ @ISA ของคลาสอ็อบเจ็กต์

  • หากไม่พบเมธอดในขั้นตอนที่ 1 หรือ 2 ดังนั้น Perl จะใช้รูทีนย่อย AUTOLOAD หากพบในทรี @ISA

  • หากยังไม่พบวิธีการจับคู่ Perl จะค้นหาวิธีการภายในคลาส UNIVERSAL (แพ็กเกจ) ที่มาเป็นส่วนหนึ่งของไลบรารี Perl มาตรฐาน

  • หากยังไม่พบเมธอด Perl จะยอมแพ้และเพิ่มข้อยกเว้นรันไทม์

ดังนั้นในการสร้างคลาส Employee ใหม่ที่จะสืบทอดเมธอดและแอตทริบิวต์จากคลาส Person ของเราเราเพียงแค่เขียนโค้ดดังนี้: เก็บโค้ดนี้ไว้ใน 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.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 ของเราอีกครั้งและดำเนินการ

#!/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 ทำสิ่งนี้ให้คุณโดยอัตโนมัติทันทีที่วัตถุอยู่นอกขอบเขต

ในกรณีที่คุณต้องการใช้ destructor ของคุณซึ่งควรดูแลการปิดไฟล์หรือทำการประมวลผลพิเศษคุณต้องกำหนดวิธีการพิเศษที่เรียกว่า DESTROY. วิธีนี้จะถูกเรียกใช้กับวัตถุก่อนที่ Perl จะปลดปล่อยหน่วยความจำที่จัดสรรให้กับมัน ในแง่อื่น ๆ เมธอด DESTROY ก็เหมือนกับวิธีอื่น ๆ และคุณสามารถใช้ตรรกะอะไรก็ได้ที่คุณต้องการในวิธีนี้

เมธอด destructor เป็นเพียงฟังก์ชันสมาชิก (รูทีนย่อย) ชื่อ DESTROY ซึ่งจะถูกเรียกโดยอัตโนมัติในกรณีต่อไปนี้ -

  • เมื่อตัวแปรของการอ้างอิงวัตถุอยู่นอกขอบเขต
  • เมื่อตัวแปรของการอ้างอิงอ็อบเจ็กต์คือ undef-ed
  • เมื่อสคริปต์สิ้นสุด
  • เมื่อตัวแปลภาษา Perl สิ้นสุดลง

ตัวอย่างเช่นคุณสามารถใส่วิธีการ DESTROY ต่อไปนี้ในชั้นเรียนของคุณ -

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

ตัวอย่าง Perl เชิงวัตถุ

นี่คืออีกหนึ่งตัวอย่างที่ดีซึ่งจะช่วยให้คุณเข้าใจ Object Oriented Concepts ของ 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