1

我现在想知道什么是做我需要的更好的模式。我试图将问题减少到最低限度,让我一步一步地解释它。

我有一个界面角色,例如:

{
    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 进行推导,但我不知道如何正确解决问题。

我可以有你的建议吗?

4

1 回答 1

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 MoosewithBEGIN

不过,在这种特殊情况下,我可能建议Likeable::OnParent您更改为更好地指定该parent方法返回 a 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(@_) }

这样,您就有信心调用likers并将do_like成功,因为必须设置属性并且它必须实现需要这些方法和文档化合同的角色。

于 2012-08-24T12:49:37.410 回答