驼鹿角色衍生

时间:2012-08-24 05:51:07

标签: perl moose

我想现在做什么是我需要的更好的模式。我尝试将问题降到最低,让我一步一步解释。

我有一个界面角色,如:

{
    package Likeable;
    use Moose::Role;

    requires 'likers';
    requires 'do_like';
}

在此之后,我需要2个抽象角色来半实现之前的接口(在这种情况下,它们实现了所有):

{
    package Likeable::OnSelf;
    use Moose::Role;

    with 'Likeable';

    has 'likers' => ( is => 'rw', isa => 'ArrayRef' );
    sub do_like { }
}

{
    package Likeable::OnParent;
    use Moose::Role;

    with 'Likeable';

    requires 'parent';

    sub likers { shift->parent->likers(@_) }
    sub do_like { shift->parent->do_like(@_) }
}

以后我需要这段代码来编译

{
    package OBJ::OnSelf;
    use Moose;
    with 'Likeable::OnSelf';
}

{
    package OBJ::OnParent;
    use Moose;
    with 'Likeable::OnParent';
    has 'parent' => ( is => 'rw', isa => 'Obj' );
}

foreach my $obj (OBJ::OnSelf->new, OBJ::OnParent->new(parent => OBJ::OnSelf->new)) {
    if ( $obj->does('Likeable') ) {
        $obj->do_like
    }
}

在我看来,问题是我试图对Moose :: Role进行推导,但我没有想法如何正确解决问题。

我可以提出你的建议吗?

1 个答案:

答案 0 :(得分:3)

您的整体角色构成确实没有问题,但我认为您收到的错误是这样的:

'Likeable::OnParent' requires the method 'parent' to be implemented by 'OBJ::OnParent' at .../Moose/Meta/Role/Application.pm line 51

问题是在调用has以检查方法之后调用with来创建属性访问方法。 (这些只是被调用的子程序,而不是实际的语言结构。)

我知道有几个很好的解决方案。我更喜欢这个:

package OBJ::OnParent;
use Moose;
has 'parent' => ( is => 'rw', isa => 'Obj' );
with 'Likeable::OnParent';

在定义属性后执行with语句。我知道的另一个选择是:

package OBJ::OnParent;
use Moose;
with 'Likeable::OnParent';

BEGIN {
    has 'parent' => ( is => 'rw', isa => 'Obj' );
}

has个调用放在BEGIN块中,这些属性会在use Moose运行之后和with之前添加到包中。我不喜欢坚持这样的BEGIN块,但这主要是个人偏好。

在这种特殊情况下,我建议您只更改Likeable::OnParent,以便更好地指定parent方法返回Likeable,这也将绕过更改的需要你的对象定义:

package Likeable::OnParent;
use Moose::Role;

with 'Likeable';

has parent => (
    is => 'rw',
    does => 'Likeable',
    required => 1,
);

sub likers { shift->parent->likers(@_) }
sub do_like { shift->parent->do_like(@_) }

通过这种方式,您可以放心,您对likersdo_like的调用将会成功,因为必须设置该属性,并且必须实现需要这些方法和已记录合同的角色。