2016-06-30 63 views
2

Base.pm駝鹿::角色與古怪覆蓋的方法

package Base; 
use Moose::Role; 

sub f { 
    my ($self) = @_; 
    print "In role.\n"; 
} 

1; 

X.pm

package X; 
use Moose; 

with 'Base'; 

around 'f' => sub { 
    my ($next, $self) = @_; 
    print "Nevermind, we are in class X.\n"; 
}; 

__PACKAGE__->meta->make_immutable; 
1; 

Y.pm

package Y; 
use Moose; 

with 'Base'; 

override 'f' => sub { 
    my ($self) = @_; 
    print "Nevermind, we are in class Y.\n"; 
}; 

__PACKAGE__->meta->make_immutable; 
1; 

然後X做的工作和Y沒有。這是一個奇怪的設計,因爲override只是around的特殊情況,作爲特殊情況也應該起作用。

任何人都可以解釋爲什麼這個設計決定,爲什麼它如此奇怪?

$ perl X.pm 
$ perl Y.pm 
Cannot add an override method if a local method is already present at /usr/lib/i386-linux-gnu/perl5/5.22/Moose/Exporter.pm line 419 
    Moose::override('f', 'CODE(0x9c002f8)') called at Y.pm line 9 

回答

3

documentation describes override爲:

的覆蓋方法是明確地說:「我會覆蓋我超這個方法」的一種方式。您可以在此方法中調用super,它將按預期工作。一個普通的方法調用和僞包可以完成同樣的事情;這真的是你的選擇。

你在做什麼與這個定義相矛盾。在角色中,f安裝在您的包中。您正試圖在同一個包中定義另一個f

事實上,你的角色被稱爲Base表明你對繼承和組合之間的區別有一些困惑。

purpose of around是包裝在當前類中的方法,無論它是否是在相同的封裝中實現或遺傳性或組成:

方法改性劑可被用於添加行爲的方法,而無需修改定義這些方法。

只是對這兩個片段的簡單閱讀使我對這個區別很清楚。

當您應用定義f的角色時,該自身將覆蓋任何繼承的方法f。如果您接着說override 'f',則表明您打算再次覆蓋f。那麼,在一個類中只能有一個方法f。哪一個應該算呢?您通過應用角色獲得的那個,還是您剛定義的那個?對於所有意圖和目的,從組成角色獲得的方法與您在類中手動定義的方法一樣。沒有理由a priori一個應該比另一個更重要。

認爲這是航空旅行。將方法修飾符視爲類:首先,商業,經濟等。因此,在第一類中,get_dinner_menu可能包裹開胃菜,糖果,甜點等。

另一方面,override就像改變航班。就好像你在說「我想在TK 1和UIA 213上飛」。沒有意義。

也許下面的腳本通過顯示around的簡單實現和重寫方法而不使用override可以使事情更加清晰。

#!/usr/bin/env perl 

use strict; 
use warnings; 

{ 
    package MyRole; 

    use Moose::Role; 

    sub f { 
     print "in role\n"; 
    } 
} 

{ 
    package X; 
    use Moose; 

    with 'MyRole'; 

    around 'f' => sub { 
     my ($orig, $self) = @_; 
     print "In wrapper\n"; 
     return $self->$orig(@_); 
    }; 

    { 
     my $f = \&f; 
     { 
      no warnings 'redefine'; 
      *f = sub { 
       my ($self) = @_; 
       print "In wrapper wrapper\n"; 
       return $self->$f(@_); 
      } 
     } 
    } 
} 

{ 
    package Y; 

    use Moose; 
    with 'MyRole'; 

    sub f { 
     print "In overridden method\n"; 
    } 
} 

print '=-=' x 22, "\n"; 

my $x = X->new; 
$x->f; 

print '=-=' x 22, "\n"; 

my $y = Y->new; 
$y->f; 

輸出:

+0

但爲什麼在地球上,'around'在這種情況下** **不工作?關於'around'的說法不能說是不合理的嗎? – porton

+0

明白了。但是在同一個類中同時使用* sub和'around'對於我來說就像是一個設計錯誤 – porton

+1

***禁止***'sub f'和'around'f ''在同一個包中,因爲組成一個提供'f'的角色在包中安裝'f'作爲一個子。所以,這種禁止使得用組合的方法來使用'around'或者是不可能的或者困難的。我沒有想太多。 –