使用 Moose 编程 / 解决的问题
外观
Perl(在 5.10 版本之前)有一个不合逻辑的 **方法解析顺序** (MRO),这在使用多重继承分派时变得明显。对 MI 分派的修复首先在 Dameon 的 NEXT
中流行起来,后来证明是一个有错误的技巧,在许多情况下都失败了。不幸的是,NEXT
被纳入了 Perl v5.7.3 的 CORE 发行版中,并且即使在今天也仍然存在于 CORE 中。Moose 使用更新的、更酷的 C 优化 Class::C3
,这是所有大于 Perl 5.95 的 Perl 中正确方法分派的新的非默认标准。[1]
在 Class::C3
和 NEXT
之前,你有 SUPER
,它比 NEXT
早了大约六个月,幸运的是从未进入 CORE。SUPER
非常愚蠢,而且几乎毫无用处,因为如果 foo 和 bar 是 baz 的兄弟姐妹和子类,你就不能在 foo 中重新分派到 bar 中的方法。
本质上,SUPER
只支持线性模式下的方法分派。NEXT
以一种怪异的方式支持它们,而且几乎毫无意义。[2] 在不了解这些怪癖的情况下,新的 Class::C3
很可能正好满足程序员的期望 - 它很直观。Class::C3
使用 C3 MRO 算法,该算法也由 Python 使用。
NEXT
和 Class::C3
之间的区别超出了本书的范围;但是,因为普通 Perl 甚至不允许方法解析,以及在 OO 范式意义上的分派,我们将展示 NEXT
来代替它。
package A;
use strict;
use warnings;
use NEXT;
sub name {
my $self = shift;
$self->{-name} = shift if @_;
return $self->{-name};
}
sub new {
my $obj = shift;
my $class = ref($obj)?ref($obj) : $obj;
my $args = shift;
my $self = bless {}, $class;
$self->{-name} = $args->{name} if( $args && ref($args) eq 'HASH' && $args->{name});
return $self;
}
sub say_name {
my $self = shift;
print "My name is ".$self->name.".\n";
}
package B
use strict;
use warnings;
use NEXT;
our @ISA = 'A'
package C
use strict;
use NEXT;
our @ISA = 'B'
sub say_name {
my $self = shift;
print "The name given to me is ".$self->name.".\n";
}
package main;
my $a = A->new({ name => 'Bob' });
# prints:
# My name is Bob
$a->say_name;
my $c = C->new({ name => 'Bill' });
#prints:
# The name given to me is Bill
$c->say_name;
package A;
use Moose; # Includes strict and warnings
# Define an attribute the object instance has.
# In this case a name, which has a type of string, and
# has a read accessor and a write accessor.
has name => ( isa => 'Str', is => 'rw' );
sub say_name {
my $self = shift;
say " my name is ".$self->name.".\n";
}
no Moose; # Clean up the namespace.
package B;
use Moose;
no Moose;
package C;
use Moose;
sub say_name {
my $self = shift;
say "The name given to me is ".$self->name.".\n";
}
no Moose;
package main;
# We get new for free.
my $a = A->new({ name => 'Bob' });
# prints:
# My name is Bob
$a->say_name;
my $c = C->new({ name => 'Bill' });
#prints:
# The name given to me is Bill
$c->say_name;