跳轉至內容

使用 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::C3NEXT 之前,你有 SUPER,它比 NEXT 早了大約六個月,幸運的是從未進入 CORE。SUPER 非常愚蠢,而且幾乎毫無用處,因為如果 foo 和 bar 是 baz 的兄弟姐妹和子類,你就不能在 foo 中重新分派到 bar 中的方法。

本質上,SUPER 只支援線性模式下的方法分派。NEXT 以一種怪異的方式支援它們,而且幾乎毫無意義。[2] 在不瞭解這些怪癖的情況下,新的 Class::C3 很可能正好滿足程式設計師的期望 - 它很直觀。Class::C3 使用 C3 MRO 演算法,該演算法也由 Python 使用。

舊方法

[編輯 | 編輯原始碼]

NEXTClass::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;

呼叫 Moose

[編輯 | 編輯原始碼]

一個例子

[編輯 | 編輯原始碼]
  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;
[編輯 | 編輯原始碼]
  1. ^ Perl 5.95 添加了一個新的 pragma mro,它使用 C3 解析。但是,這個 pragma 是可選的,它提供了一些工具給你,所有這些工具都可以使用,同時保持與舊版本的 Perl 的向後相容性,使用 MRO::Compat。
  2. ^ 那個幾乎毫無意義的方法叫做深度優先搜尋 (DFS)。DFS 是 Perl 中 C3 之前的 MRO。簡而言之,它無法以合理的方式處理任何形式的三角繼承。
華夏公益教科書