【问题标题】:Perl module that accepts list and creates objects接受列表并创建对象的 Perl 模块
【发布时间】:2020-10-25 14:13:01
【问题描述】:

我正在研究一个大学问题(在 Perl 中)。我们正在创建模块,我需要编写一个简单的模块,该模块“具有四个属性的 get/set 方法:lastname、firstname、full_name 和一个子对象列表”。

我想我已经把它记下来了,但让我感到震惊的是那些也是人的孩子的名单。我猜模块需要接受一个列表然后创建一个对象列表? Python 是我的核心语言,所以这个语言让我很吃惊。 get/set 方法工作正常。有什么想法吗?

我的模块在这里...

#!/usr/bin/perl

package Person;

sub new
{
    my $class = shift;
    my $self = {
        _firstName => shift,
        _lastName  => shift,
    };
    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};
}

sub setLastName {
    my ( $self, $lastName ) = @_;
    $self->{_lastName} = $lastName if defined($lastName);
    return $self->{_lastName};
}

sub getLastName {
    my( $self ) = @_;
    return $self->{_lastName};
}

sub getFullName {
    my( $self ) = @_;
    return $self->{_lastName}.",".$self->{_firstName};
}

1;

我的代码在这里.....

#!/usr/bin/perl

use Person;

$object = new Person("Elvis","Presley");
# Get first name which is set using constructor.
$firstName = $object->getFirstName();
$lastName = $object->getLastName();
$fullname = $object->getFullName();

print "(Getting) First Name is : $firstName\n";
print "(Getting) Last Name is: $lastName\n";
print "(Getting) Full Name is: $fullname\n";

【问题讨论】:

  • “我猜模块需要接受一个列表,然后创建一个对象列表?” 如果你传递一个Person对象列表,那么就没有什么可做的了创造。您的对象需要另一个字段,_children,它是一个数组。您可以在构造函数_children => [] 中使用空数组对其进行初始化,并使用另一个setter 将其添加到其中。您将以与创建 $object 相同的方式创建多个子代,并为它们分配类似 $object->setChildren($kid1, $kid2, $kid3)

标签: perl oop module package


【解决方案1】:

只需在 setter 中使用对象列表:

#! /usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

{   package Person;

    sub new {
        my $class = shift;
        my $self = {
            _firstName => shift,
            _lastName  => shift,
            _children => [],
        };
        return bless $self, $class
    }

    sub setFirstName {
        my ($self, $firstName) = @_;
        $self->{_firstName} = $firstName if defined $firstName;
        return $self->{_firstName}
    }

    sub getFirstName {
        my ($self) = @_;
        return $self->{_firstName}
    }

    sub setLastName {
        my ($self, $lastName) = @_;
        $self->{_lastName} = $lastName if defined $lastName;
        return $self->{_lastName}
    }

    sub getLastName {
        my ($self) = @_;
        return $self->{_lastName}
    }

    sub getFullName {
        my ($self) = @_;
        return $self->{_lastName} . ', ' . $self->{_firstName}
    }

    sub getChildren {
        my ($self) = @_;
        return @{ $self->{_children} }
    }

    sub setChildren {
        my ($self, @children) = @_;
        $self->{_children} = [ @children ];
    }

}

my $object = 'Person'->new('Elvis', 'Presley');

# Get first name which is set using constructor.
my $firstName = $object->getFirstName;
my $lastName = $object->getLastName;
my $fullname = $object->getFullName;

$object->setChildren('Person'->new('Lisa', 'Presley'),
                     'Person'->new('Deborah', 'Presley'));

say "(Getting) First Name is: $firstName";
say "(Getting) Last Name is: $lastName";
say "(Getting) Full Name is: $fullname";

say "Children: ";
say $_->getFullName for $object->getChildren;

请注意,有些模块可以让构建对象更容易,例如Moo:

#! /usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

{   package Person;
    use Moo;

    has first_name => (is => 'ro');
    has last_name => (is => 'ro');
    has full_name => (is => 'lazy');
    has _children => (is => 'ro',
                      init_arg => undef,
                      default => sub { [] });

    sub _build_full_name {
        my ($self) = @_;
        return $self->last_name . ', ' . $self->first_name
    }

    sub add_child {
        my ($self, $child) = @_;
        push @{ $self->_children }, $child
    }

    sub children {
        my ($self) = @_;
        return @{ $self->_children }
    }

}

my $object = 'Person'->new(first_name => 'Elvis',
                           last_name  => 'Presley');

# Get first name which is set using constructor.
my $firstName = $object->first_name;
my $lastName = $object->last_name;
my $fullname = $object->full_name;

$object->add_child($_) for 'Person'->new(first_name => 'Lisa',
                                         last_name => 'Presley'),
                           'Person'->new(first_name => 'Deborah',
                                         last_name => 'Presley');

say "(Getting) First Name is: $firstName";
say "(Getting) Last Name is: $lastName";
say "(Getting) Full Name is: $fullname";

say "Children: ";
say $_->full_name for $object->children;

【讨论】:

    【解决方案2】:

    要求意味着应该有一个可以容纳对象集合的属性,因此是对数组的引用。这是在构造函数中定义的

    sub new
    {
        my $class = shift;
        my $self = {
            _firstName => shift,
            _lastName  => shift,
            _children  => [ @_ ],
        };
        bless $self, $class;
        return $self;
    }
    

    其中[ ] 创建一个匿名数组并返回其引用,这是一个标量,因此可用于哈希值。其中的 @_ 在类和名称被 shift-ed 之后包含可选的其余参数(Person 对象)。

    需要检查参数,但是当它们在位置上使用时,这对于简单的列表会变得很困难。相反,请考虑使用named parameters,即。将 hash(ref) 传递给构造函数,通过它可以轻松检查哪些参数已提供或未提供。

    接下来,你需要一个方法来给这个属性添加子元素,例如

    sub add_children {
        my ($self, @children) = @_;             # and check what's passed
        push @{$self->{_children}}, @children;
        return $self;                           # for chaining if desired
    }
    

    最后,当您调用此方法时,您将 Person 类的对象传递给它

    use warnings;
    use strict;
    
    use Person;
    
    my $object = Person->new('Elvis', 'Presley');
    
    my $child = Person->new('First', 'Last');
    
    $object->add_children( $child );
    

    或者,如果在其余代码中没有使用$child 变量(对象)

    $object->add_children( Person->new(...) );
    

    您可以添加子列表add_children($c1, $c2, ...),例如用于初始填充数据结构,或者可以在它们出现时单独添加它们。

    Person 子级列表也可以在构造函数中使用

    my $obj = Person->new('First', 'Last', $c1, $c2,...);
    

    使用提到的命名参数,这变得更加清晰和灵活,这些命名参数在构造函数中被解包和排序。但更重要的是,一旦您了解了 Perl 的本机 OO 系统,请查看模块,最好是 Moose 及其轻量级对应物 Moo

    评论

    • 总是开头有use warnings;use strict;

    • 不要使用indirect object notation

       my $obj = new ClassName(...);   # DO NOT USE
      

    this postthis great example。它可以用于调用构造函数这一事实实际上是对其其他合法用途的滥用。使用普通的方法调用

        my $obj = ClassName->new(...);
    

    【讨论】:

      【解决方案3】:

      很高兴你的大学教你 Perl,但有点令人失望的是他们教你 Perl OO 的“经典”版本,而在现实世界中,Perl 中的大多数 OO 工作都使用像 Moo 或 @ 这样的框架987654322@.

      出于兴趣,我在下面包含了一个 Moo 版本的 Person 对象:

      package Person;
      
      use Moo;
      use Types::Standard qw[Str ArrayRef Object];
      
      has first_name => (
        is => 'rw',
        isa => Str,
        required => 1,
      );
      
      has last_name => (
        is => 'rw',
        isa => Str,
        required => 1,
      );
      
      has children => (
        is => 'rw',
        isa => ArrayRef[Object],
      );
      
      sub full_name {
        my $self = shift;
      
        return $self->first_name . ' ' . $self->last_name;
      }
      
      1;
      

      这是一个简单的测试程序:

      #!/usr/bin/perl
      
      use strict;
      use warnings;
      use feature 'say';
      
      use Person;
      
      my $elvis = Person->new(
        first_name => "Elvis",
        last_name  => "Presley",
        children   => [Person->new(
          first_name => 'Lisa Marie',
          last_name  => 'Presley',
        )],
      );
      
      my $first_name = $elvis->first_name;
      my $last_name  = $elvis->last_name;
      my $full_name  = $elvis->full_name;
      
      say "(Getting) First Name is : $first_name";
      say "(Getting) Last Name is: $last_name";
      say "(Getting) Full Name is: $full_name";
      
      say "Elvis's first child is ", $elvis->children->[0]->full_name;
      

      需要注意的几点:

      • 始终在您的代码中包含 use strictuse warnings
      • 始终使用Class->new 而不是new Class
      • Perl 程序员更喜欢snake_case 而不是camelCase
      • Moo 喜欢你在对象构造函数中使用命名参数
      • 声明性属性(使用has)的重复性远低于编写所有自己的getter 和setter 方法
      • 与单独的 get_foo()set_foo() 方法相比,程序员倾向于使用单一方法(foo() 可用作 getter 和 setter。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-11
        • 1970-01-01
        • 1970-01-01
        • 2010-10-07
        • 2015-01-18
        相关资源
        最近更新 更多