首页 > 解决方案 > Perl 类属性继承

问题描述

我有类属性,例如,某些基类中创建的对象的计数器,

package A;
our $counter = Counter->new; # not just a counter in fact, so initialization code should be inherited by descendants as well

sub new {
    $counter++;
    bless {}
}
sub get_counter {
    $counter
}

package B;
use base 'A';

package main;
B->get_counter();

我希望包 B 有他自己的这个类属性的副本(例如,只计算 B 类的对象),并且从包 A 继承的所有方法都应该处理这个副本。在普通 perl 和 Moo/Moose 中实现这一点的正确方法是什么?似乎 MooX::ClassAttribute 不能被继承。一个丑陋的解决方案是在每个后​​代中重复属性初始化代码,并在祖先的方法中使用像 ${"${class}::counter"} 这样的符号取消引用来使用实际包名访问这个属性。但似乎应该有更优雅的方式。

标签: perloopinheritance

解决方案


默认的 Perl 对象模型没有类属性的概念。并且没有像“当一个新的子类被创建时,运行这个代码”这样的钩子。

相反,基类可以使用类名作为键来维护计数器的散列:

package A;
my %counters;

sub new {
  my ($class) = @_;
  my $counter = $counters{$class} //= Counter->new;
  $counter++;
  return bless {} => $class;
}

sub get_counter {
  my ($self_or_class) = @_;
  my $class = (ref $self_or_class) || $self_or_class;
  $counters{$class};
}

package B;
use parent -norequire, 'A';

当创建子类的实例时,这将创建一个新的计数器。请注意,方法的第一个参数是类名或对象实例。我们需要使用它new()作为哈希键。在get_counter()我写这个的方式中,该方法可以在类和对象上调用以达到相同的效果。

一种类似的技术被称为由内而外的对象,其中将对象字段存储在类持有的哈希中,以便对象本身不包含任何数据。

(为什么parent而不是base?该parent模块仅进行继承,而base还与fields您不应该使用的 pragma 集成。)


推荐阅读