修改或提供方法的角色

时间:2015-04-24 16:12:54

标签: perl moose

如果我想要一个角色来修改一个方法,如果消费类没有它,或者提供一个消费类没有的默认方法怎么办?

在一种情况下,使用方法修饰符起作用。在另一种情况下,只需定义一个普通方法即可。是否有一种方法适用于这两种情况?

具体例子:

package UsualFavorites;
use Moose::Role;

around favorite_things {
    my ($self, $orig) = @_;
    $self->$orig(), qw/doorbells sleighbells/;
}

如果消费类没有定义favorite_things方法,我希望它最终得到一个只返回favorite_things的{​​{1}}方法。

3 个答案:

答案 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

请注意,如果您的角色被其他参数化角色使用,或者您的角色应用于对象实例,则必须执行其他体操操作。 EtherHow 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);

所以我都有我在角色中有默认实现,它似乎有效。