我该如何创建一个Perl类?

20

我正在编写Perl类来从脚本中删除冗余,并且由于Perl有很多制作类的方式,我一直在努力正确地制作类。那么,有没有关于类的最佳实践示例呢?

我最大的问题是:如果模块中不应该有全局变量,那么如何在模块的sub()之间使用变量呢?就像Java中的self->foo = 10;

基本上,只要给我一个用Java或C#甚至C++编写的类,在Perl中也写出相同的代码。另外,展示如何正确使用私有、受保护和公共类变量会得到额外的积分。继承和接口可能也会对我有所帮助。


1
Perl的面向对象特性最好说有点欠缺... :P 我会去看一个简单的.pm模块,看看它们是如何实现的。 - Charles Ma
4个回答

30

创建 Perl 对象的典型方式是将哈希引用“bless”为对象。随后,对象实例可以针对其自身一组哈希键存储数据。

package SampleObject;

use strict;
use warnings;

sub new {
    my ($class, %args) = @_;
    return bless { %args }, $class;
}

sub sample_method {
    my ($self) = @_;
    print $self->{sample_data};
}

并且使用:

my $obj = SampleObject->new( sample_data => 'hello world',
                             more_data   => 'blah blah blah' );
$obj->sample_method();

另外,也可以添加访问器/修改器方法(参见Class :: Accessor,Class :: Accessor :: Chained等),这些方法易于设置 - 这样可以更容易地验证数据并添加封装(在Perl中没有强制要求,您必须确保代码不会绕过适当的访问器/修改器并直接访问blessed哈希引用中的数据)。


似乎是两个答案中最优雅的一个。 - kthakore

27

Perl很容易,但我对其他语言有点生疏,稍后会更新。这是一个简单的Perl类:

#!/usr/bin/perl

package Person;

use strict;
use warnings;
use Carp;

sub new {
    my $class = shift;
    my $self  = { @_ };
    croak "bad arguments" unless defined $self->{firstname} and defined $self->{lastname}; 
    return bless $self, $class; #this is what makes a reference into an object
}

sub name {
    my $self = shift;
    return "$self->{firstname} $self->{lastname}";
}

#and here is some code that uses it
package main;

my $person = Person->new(firstname => "Chas.", lastname => "Owens");
print $person->name, "\n";

以下是使用新的 Moose 风格对象编写的相同类:

#!/usr/bin/perl

package Person;

use Moose; #does use strict; use warnings; for you

has firstname => ( is => 'rw', isa => 'Str', required => 1 );
has lastname  => ( is => 'rw', isa => 'Str', required => 1 );

sub name {
    my $self = shift;
    return $self->firstname . " " . $self->lastname;
}

#and here is some code that uses it
package main;

my $person = Person->new(firstname => "Chas.", lastname => "Owens");
print $person->name, "\n";

MooseX::Declare消除了更多代码的需求,并使代码看起来更加美观:

#!/usr/bin/perl

use MooseX::Declare;

class Person {
    has firstname => ( is => 'rw', isa => 'Str', required => 1 );
    has lastname  => ( is => 'rw', isa => 'Str', required => 1 );

    method name {
            return $self->firstname . " " . $self->lastname;
    }
}

#and here is some code that uses it
package main;

my $person = Person->new(firstname => "Chas.", lastname => "Owens");
print $person->name, "\n";

简单说明一下,这两个类是我编写的第一批 Moose 类。这里还有一些非常生疏的 C++ 代码(别被它划伤了,否则你需要注射破伤风疫苗):

#include <stdio.h>
#include <string.h>

class Person {
    char* firstname;
    char* lastname;

    public:
    Person(char* first, char* last) {
        firstname = first;
        lastname  = last;
    }

    char* name(void) {
        int len = strlen(firstname) + strlen(lastname) + 1;
        char* name = new char[len];
        name[0] = '\0';
        strcat(name, firstname);
        strcat(name, " ");
        strcat(name, lastname);
        return name;
    }
};

int main(void) {
    Person* p    = new Person("Chas.", "Owens");
    char*   name = p->name();
    printf("%s\n", name);
    delete name;
    delete p;
    return 0;
}

17

我意识到这是一个常见的答案,但它实际上并没有向我展示如何制作类似于其他面向对象编程语言的自己的类。 - kthakore
2
你说得对,他给了你展示如何做的链接。为什么要从其他地方复制/粘贴浪费字节,当一个链接更好呢。 - mpeters
4
@mpeters 因为链接会失效。如果该链接因任何原因失效,这个答案几乎就没有价值了。这在StackOverflow FAQ中有说明。 - MattDavey

4
除了Moose,已经有人提到过...
如果你只是谈论类(不是对象),通常使用限定于文件范围的词法变量创建类数据,并使用每个文件一个类。您可以创建访问器方法来处理它们。有多种方法可以处理。
不过,看起来你需要从Intermediate Perl或Damian Conway的Object Oriented Perl开始。有太多需要解释的内容,没有人会花时间在Stackoverflow答案中重现所有内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接