【问题标题】:Perl class attribute inheritancePerl 类属性继承
【发布时间】:2018-05-20 01:58:26
【问题描述】:

我有类属性,例如。 g.,在某个基类中创建对象的计数器,

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"} 这样的符号取消引用来使用实际包名访问这个属性。但似乎应该有更优雅的方式。

【问题讨论】:

    标签: perl oop inheritance


    【解决方案1】:

    默认的 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 而不是baseparent 模块只做继承,而base 还集成了你不应该使用的fields pragma。)

    【讨论】:

    • 谢谢。是否可以使用高级对象包(如 Moose 及其较小的克隆)中的元类技术以原始形式实现此任务?
    • 可能,但我对 Moose 元对象协议 (MOP) 不够熟悉。 Moo 没有 MOP。我希望其他人能提供基于 Moose 的答案。
    猜你喜欢
    • 2011-05-09
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    • 2014-10-06
    • 2013-04-13
    • 2015-05-08
    • 2013-09-02
    • 1970-01-01
    相关资源
    最近更新 更多