การเขียนโปรแกรมเชิงวัตถุใน 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