目录

Perl - 面向对象( Object Oriented)

我们已经研究了Perl和Perl匿名数组和散列中的引用。 Perl中的面向对象概念非常基于引用和匿名数组和散列。 让我们开始学习面向对象Perl的基本概念。

对象基础知识

从Perl处理对象的角度来看,有三个主要术语。 术语是对象,类和方法。

  • Perl中的object仅仅是对知道它属于哪个类的数据类型的引用。 该对象存储为标量变量中的引用。 因为标量只包含对象的引用,所以相同的标量可以在不同的类中保存不同的对象。

  • 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。

$object = new Person( "Mohammad", "Saleem", 23234345);

如果您不想为任何类变量赋值,可以在consturctor中使用简单哈希。 例如 -

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.

继承 (Inheritance)

面向对象编程具有非常好的和有用的概念,称为继承。 继承只是意味着父类的属性和方法可供子类使用。 因此,您不必一次又一次地编写相同的代码,您可以继承父类。

例如,我们可以有一个Employee类,它继承自Person。 这被称为“isa”关系,因为员工是一个人。 Perl有一个特殊变量@ISA来帮助解决这个问题。 @ISA管理(方法)继承。

以下是使用继承时要考虑的重点 -

  • Perl在指定对象的类中搜索给定的方法或属性,即变量。

  • Perl搜索对象类的@ISA数组中定义的类。

  • 如果在步骤1或2中找不到任何方法,则Perl使用AUTOLOAD子例程(如果在@ISA树中找到一个子例程)。

  • 如果仍然找不到匹配方法,则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 Class具有从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的形式访问缺少的子例程的名称。

默认自动加载功能对于错误处理非常有用。 以下是实现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的成员函数(子例程),在以下情况下将自动调用 -

  • 当对象引用的变量超出范围时。
  • 当对象引用的变量未被删除时。
  • When the script terminates
  • 当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
↑回到顶部↑
WIKI教程 @2018