使用 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;