Perl 面向对象编程






4.49/5 (35投票s)
Perl 面向对象编程的基础知识
Camel POOP
大多数人可能不知道 Perl 支持面向对象编程。如果你使用过其他面向对象编程语言,如 Java 或 C++,或者接触过面向对象,那么 Perl 中的面向对象编程与它们完全不同。要在 Perl 中进行真正有用的面向对象编程,你只需要遵循 Larry Wall 在 Object Oriented Perl 中提出的三个简单规则。
面向对象程序员熟悉对象和类的概念,但我将在这里快速回顾一下。对象是提供对数据访问或修改的事物。类描述了特定类型对象的属性以及如何访问和修改这些对象。方法是访问或修改对象数据的方式。对象是类的实例。
一个例子是 HR 系统中的 Person
类。Person
类描述了一个人的属性,如姓名、地址、职称、社会安全号码、ID 等。一个特定的类实例或对象将封装一个特定人的数据,例如姓名、职称、社会安全号码、地址等。一些访问该对象数据的方法包括 name
、address
等。
包裹递送
要创建 Perl 中的类,我们首先构建一个包。包是一个包含用户定义的变量和子程序的独立单元,可以反复重用。它们在 Perl 程序中提供了独立的命名空间,使子程序和变量不会与其他包中的冲突。
要在 Perl 中声明一个名为 Person
的类,我们这样做:
package Person;
就这样!包定义的范围一直延伸到文件末尾,或者直到遇到另一个 package
关键字。现在还没有什么用处,我们继续下一节。
方法之道
方法是访问或修改对象数据的方式。在 Perl 中,方法只是在特定包中定义的子程序。因此,要定义一个打印我们的 Person
对象的方法,我们这样做:
sub print {
my ($self) = @_;
#print Person info
printf( "Name:%s %s\n\n", $self->firstName, $self->lastName );
}
现在,子程序 print
与 Person
包相关联。要调用 Person
对象上的 print
方法,我们使用 Perl 的“箭头”符号。如果变量 $khurt
包含一个 Person
对象,我们将通过编写以下代码来调用该对象上的 print
:
$khurt->print();
当调用对象方法时,对象引用会与任何其他参数一起传递。这一点很重要,因为方法现在可以访问它要操作的对象。
我们如何创建调用对象?
保佑我,神父,
我们需要一个对象构造函数来创建类的实例(对象)。这个构造函数是在包内定义的一个方法。大多数程序员选择将此对象构造函数方法命名为 new
,但在 Perl 中,可以使用任何名称。
在 Perl 中,任何 Perl 变量都可以用作对象。大多数 Perl 程序员选择使用数组或哈希的引用。
让我们使用 Perl
哈希引用为我们的 Person
类创建构造函数;
#constructor
sub new {
my $self = {
_firstName => undef,
_lastName => undef,
_ssn => undef,
_address => undef
};
bless $self, 'Person';
return $self;
}
我们做了什么?我们创建了一个名为 new
的子程序,它与 Person
包相关联。哈希引用 $self
的条目成为我们对象的属性。然后,我们在哈希引用上使用 bless
函数。bless
函数接受两个参数:要标记的变量的引用和一个包含类名的字符串。这表明该变量现在属于 Person
类。
创建我们 Person
对象的实例
my $khurt = new Person();
我们还没有定义访问器方法,也没有对输入值、键或匿名哈希引用进行任何错误检查,但我们已经有了 Perl Person
OO 框架的开始。为了使我们的构造函数更灵活,并使我们的类可继承(稍后详述),我们可以定义它来使用 $class
变量来 bless 哈希引用。
#constructor
sub new {
my ($class) = @_;
my $self = {
_firstName => undef,
_lastName => undef,
_ssn => undef,
_address => undef
};
bless $self, $class;
return $self;
}
其他面向对象语言有数据安全的概念,以防止程序员直接更改对象数据,并提供访问器方法来修改对象数据。Perl 没有 private
变量,但我们仍然可以使用访问器方法,并要求程序员不要乱动我们的对象内部。
我们应该为我们的 Person 类的对象属性提供访问器方法;name
、address
、title
和 SSN
。
#class Person
package Person;
use strict;
use Address; #Person class will contain an Address
#constructor
sub new {
my ($class) = @_;
my $self = {
_firstName => undef,
_lastName => undef,
_ssn => undef,
_address => undef
};
bless $self, $class;
return $self;
}
#accessor method for Person first name
sub firstName {
my ( $self, $firstName ) = @_;
$self->{_firstName} = $firstName if defined($firstName);
return $self->{_firstName};
}
#accessor method for Person last name
sub lastName {
my ( $self, $lastName ) = @_;
$self->{_lastName} = $lastName if defined($lastName);
return $self->{_lastName};
}
#accessor method for Person address
sub address {
my ( $self, $address ) = @_;
$self->{_address} = $address if defined($address);
return $self->{_address};
}
#accessor method for Person social security number
sub ssn {
my ( $self, $ssn ) = @_;
$self->{_ssn} = $ssn if defined($ssn);
return $self->{_ssn};
}
sub print {
my ($self) = @_;
#print Person info
printf( "Name:%s %s\n\n", $self->firstName, $self->lastName );
}
1;
生宝宝
面向对象编程有时涉及继承。继承意味着允许一个称为 Child
的类从另一个称为 Parent
的类继承方法和属性,这样您就不必重复编写相同的代码。例如,我们可以有一个 Employee
类,它继承自 Person
。这被称为“isa
”关系,因为 employee
是一个 person
。Perl 有一个特殊变量 @ISA
来帮助处理这个问题。 @ISA
管理(方法)继承。因此,要创建一个将从我们的 Person
类继承方法和属性的新 Employee
类,我们编写:
# class Employee
package Employee;
use Person;
use strict;
our @ISA = qw(Person); # inherits from Person
我们已经加载了 Person 类,并声明 Employee
类从中继承方法。我们没有为 Employee
声明任何方法,但 Employee
对象将像 Person
对象一样运行。我们应该能够编写代码
#create Employee class instance
my $khurt = new Employee();
#set object attributes
$khurt->firstName('Khurt');
$khurt->lastName('Williams');
而无需进行任何其他更改。
现在让我们添加一些方法。
# class Employee
package Employee;
use Person;
use strict;
our @ISA = qw(Person); # inherits from Person
#constructor
sub new {
my ($class) = @_;
#call the constructor of the parent class, Person.
my $self = $class->SUPER::new();
$self->{_id} = undef;
$self->{_title} = undef;
bless $self, $class;
return $self;
}
#accessor method for id
sub id {
my ( $self, $id ) = @_;
$self->{_id} = $id if defined($id);
return ( $self->{_id} );
}
#accessor method for title
sub title {
my ( $self, $title ) = @_;
$self->{_title} = $title if defined($title);
return ( $self->{_title} );
}
sub print {
my ($self) = @_;
# we will call the print method of the parent class
$self->SUPER::print;
$self->address->print;
}
1;
查看代码,您会注意到我们有一个 new
方法和一个 print
方法。子类及其父类都有相同的方法定义。我们已经用子类的方法覆盖了父类的方法。当在 Employee
对象上调用这些方法时,我们将获得 Employee
类的该方法的版本。这种使用现有对象的 [方法](https://codeproject.org.cn/Articles/30773/Object-Oriented-Programming-in-Perl-Part) 并修改它的概念称为多态。
整合
现在我们有了完整的类集,我们可以编写一个小程序来测试它们。
use strict;
use warnings;
use diagnostics;
use Employee;
#create Employee class instance
my $khurt = eval { new Employee(); } or die ($@);
#set object attributes
$khurt->firstName('Khurt');
$khurt->lastName('Williams');
$khurt->id(1001);
$khurt->title('Executive Director');
$khurt->address( new Address() );
$khurt->address->street('10 Anywhere Lane');
$khurt->address->city('Anytown');
$khurt->address->state('NJ');
$khurt->address->zip('12345');
#display Employee info
$khurt->print();
让我们执行我们的代码并查看输出
$ ./test.pl
Name:Khurt Williams
Address:10 Anywhere Lane
Anytown, NJ 12345
它有效!我们涵盖了 Perl 面向对象编程的基础知识,希望本文内容丰富且有用。