65.9K
CodeProject 正在变化。 阅读更多。
Home

Perl 面向对象编程

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.49/5 (35投票s)

2002年11月6日

CPOL

5分钟阅读

viewsIcon

525244

downloadIcon

1857

Perl 面向对象编程的基础知识

Camel POOP

大多数人可能不知道 Perl 支持面向对象编程。如果你使用过其他面向对象编程语言,如 Java 或 C++,或者接触过面向对象,那么 Perl 中的面向对象编程与它们完全不同。要在 Perl 中进行真正有用的面向对象编程,你只需要遵循 Larry Wall 在 Object Oriented Perl 中提出的三个简单规则。

面向对象程序员熟悉对象和类的概念,但我将在这里快速回顾一下。对象是提供对数据访问或修改的事物。类描述了特定类型对象的属性以及如何访问和修改这些对象。方法是访问或修改对象数据的方式。对象是类的实例。

一个例子是 HR 系统中的 Person 类。Person 类描述了一个人的属性,如姓名、地址、职称、社会安全号码、ID 等。一个特定的类实例或对象将封装一个特定人的数据,例如姓名、职称、社会安全号码、地址等。一些访问该对象数据的方法包括 nameaddress 等。

包裹递送

要创建 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 );
}

现在,子程序 printPerson 包相关联。要调用 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 类的对象属性提供访问器方法;nameaddresstitleSSN

#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 面向对象编程的基础知识,希望本文内容丰富且有用。

© . All rights reserved.