如果我想要一个角色来修改一个方法,如果消费类没有它,或者提供一个消费类没有的默认方法怎么办?
在一种情况下,使用方法修饰符起作用。在另一种情况下,只需定义一个普通方法即可。是否有一种方法适用于这两种情况?
具体例子:
package UsualFavorites;
use Moose::Role;
around favorite_things {
my ($self, $orig) = @_;
$self->$orig(), qw/doorbells sleighbells/;
}
如果消费类没有定义favorite_things
方法,我希望它最终得到一个只返回favorite_things
的{{1}}方法。
答案 0 :(得分:3)
你可以使用MooseX::Role::Parameterized
执行此操作:
Favorites.pm
package Favorites;
use MooseX::Role::Parameterized;
parameter method_name => (
isa => 'Str',
default => 'favorite_things'
);
role {
my $p = shift;
my %args = @_;
my $consumer = $args{consumer};
my $method_name = $p->method_name;
my @default_values = qw/doorbells sleighbells/;
if ( $consumer->find_method_by_name($method_name) ) {
around $method_name => sub {
my $orig = shift;
my $self = shift;
$self->$orig(@_), @default_values;
};
}
else {
method $method_name => sub {
my $self = shift;
return @default_values;
};
}
};
no Moose::Role;
1;
Santa.pm(圣诞老人喜欢门铃,对吧?):
package Santa;
use Moose;
use namespace::autoclean;
with 'Favorites';
__PACKAGE__->meta->make_immutable;
1;
ACDC.pm
package ACDC;
use Moose;
use namespace::autoclean;
with 'Favorites';
sub favorite_things {
my $self = shift;
return 'Hells Bells';
}
__PACKAGE__->meta->make_immutable;
1;
favorites_test
use strict;
use warnings;
use 5.010;
use ACDC;
use Santa;
my $kris_kringle = Santa->new;
say 'Santa likes ', join(', ', $kris_kringle->favorite_things);
my $acdc = ACDC->new;
say 'AC/DC likes ', join(', ', $acdc->favorite_things);
Santa likes doorbells, sleighbells
AC/DC likes Hells Bells, doorbells, sleighbells
请注意,如果您的角色被其他参数化角色使用,或者您的角色应用于对象实例,则必须执行其他体操操作。 Ether在How can I access the meta class of the module my Moose role is being applied to?中描述了这两种情况,并在评论中注明:
我不再认为上述是“最佳实践”,并且确实已经重构了所有这些(ab)MXRP的使用。恕我直言,如果你需要从一个角色中访问
$meta
,你的设计中就会有一些臭的东西。
有什么理由你不能简单地要求favorite_things
吗?
答案 1 :(得分:3)
只需在角色中定义方法即可。如果类具有相同名称的方法,则将忽略该角色中的方法。
package UsualFavorites;
use Moose::Role;
sub favorite_things {
return ();
}
around favorite_things => sub {
my ($orig, $self) = @_;
return ($self->$orig(), qw/doorbells sleighbells/);
};
package Consumer;
use Moose;
with 'UsualFavorites';
sub favorite_things {
return qw/shipbells/;
}
答案 2 :(得分:1)
采取ThisSuitIsBlackNot的解决方案并简化一点,我有:
package UsualFavorites;
use Moose::Role;
use strict;
use warnings;
around favorite_things => sub {
my ($orig, $self) = @_;
$self->$orig(), qw/doorbells sleighbells/;
};
sub favorite_things { () }
package Santa;
use Moose;
use strict;
use warnings;
with 'UsualFavorites';
package ACDC;
use Moose;
use strict;
use warnings;
with 'UsualFavorites';
sub favorite_things {
my $self = shift;
return 'Hells Bells';
}
package main;
use strict;
use warnings;
use 5.010;
my $kris_kringle = Santa->new;
say 'Santa likes ', join(', ', $kris_kringle->favorite_things);
my $acdc = ACDC->new;
say 'AC/DC likes ', join(', ', $acdc->favorite_things);
所以我都有和我在角色中有默认实现,它似乎有效。