2016-06-30 14 views
2

Base.pm:Moose :: Роль странность с перекрытыми методами

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 в этом методе, и он будет работать, как ожидалось. То же самое можно сделать с помощью обычного вызова метода и псевдопакета 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' в этом случае ** ** ли работать? Нельзя ли так сказать «вокруг», чтобы оправдать, что он не должен работать? – porton

+0

Получил. Но разрешение * как * 'sub', так и' around' для одного и того же метода в одном классе выглядит как ошибка дизайна для меня – porton

+1

Нет ничего, что можно было бы получить ***, запрещающее *** 'sub f' и' around 'f ''в том же пакете, потому что создавая роль, которая предоставляет' f' устанавливает 'f' в качестве суб в пакете. Таким образом, этот запрет делает использование 'around' с составленными методами невозможным или трудным. Я не слишком много думал об этом. –