我想现在做什么是我需要的更好的模式。我尝试将问题降到最低,让我一步一步解释。
我有一个界面角色,如:
{
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进行推导,但我没有想法如何正确解决问题。
我可以提出你的建议吗?
答案 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(@_) }
通过这种方式,您可以放心,您对likers
和do_like
的调用将会成功,因为必须设置该属性,并且必须实现需要这些方法和已记录合同的角色。