我应该如何访问Perl子类中的实例数据?

时间:2009-08-04 03:08:12

标签: perl

我正在扩展一个模块,我想要一些关于良好实践的技巧。特别是命名空间冲突:它们究竟是什么以及如何避免它们。

扩展时,我是否应该访问SUPER类中的变量并且只通过访问器或对象方法改变其状态?如果没有(或有限)访问者怎么办?我是否“允许”直接访问这些对象变量?

干杯!

2 个答案:

答案 0 :(得分:6)

最好只通过访问器访问内容,因为这可以防止超类的实现中的更改影响子类。你应该远离任何以下划线开头的东西。那些东西都是私人的。尽量远离任何未记录的内容。依靠这些东西会让你陷入困境。另外,请考虑使用has-a与is-a的关系。

让我们想象一个小部件类。这个类有名称和价格成员(请注意,这些都不是特别好的代码,我只是抛出了一个版本而不考虑它的例子):

package Widget;

use strict;
use warnings;

sub new {
   my $class = shift;
   my %args  = @_;

   return bless {
       price => $args{price} || 0,
       name  => $args{name}  || "unkown",
   }, $class;
}

sub price { shift->{price} }
sub name  { shift->{name}  }

1;

您决定子窗口小部件以添加权重成员:

package Widget::WithWeight;

use strict;
use warnings;

use base 'Widget';

sub new {
    my $class = shift;
    my %args  = @_;
    my $self  = $class->SUPER::new(%args);
    $self->{weight} = $args{weight} || 0;
    return bless $self, $class;
}

sub weight { shift->{weight} }

sub price_per_pound {
    my $self = shift;
    return $self->{price}/$self->{weight};
}

1;

现在假设第一个模块的作者改变了他/她关于如何存储价格的想法。也许它被存储为浮点数,作者意识到将它存储为整数个便士会更好:

package Widget;

use strict;
use warnings;

sub new {
   my $class = shift;
   my %args  = @_;

   if ($args{price}) {           
       $args{price} =~ s/[.]//;
   }

   return bless {
       price => $args{price} || "000",
       name  => $args{name}  || "unkown",
   }, $class;
}

sub price { 
    my $self = shift;
    my $price = $self->{price};
    substr($price, -2, 0) = ".";
    return $price;
}

sub name  { shift->{name}  }

1;

突然间,您的测试将开始失败,但如果您使用了price访问者,那么您将完全不受此更改的影响。

答案 1 :(得分:1)

如果从两个模块继承到一个模块并且它们都提供(导出)相同的子模块,则会发生命名空间冲突。

我建议你看看Moose,它是Perl的扩展,为你提供类和角色。如果使用角色,则可以避免许多冲突。见http://www.iinteractive.com/moose/

Moose还为类变量创建了自动访问器,使得从继承类访问它们更安全。