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 Moose前に、属性がパッケージに追加されますwith。このようなブロックに固執するのは好きではありませんBEGINが、それは主に個人的な好みです.

ただし、この特定のケースでは、メソッドが を返すLikeable::OnParentことをより適切に指定するように変更することをお勧めします。これにより、オブジェクト定義を変更する必要も回避されます。parentLikeable

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(@_) }

このようにして、属性を設定する必要があり、それらのメソッドと文書化されたコントラクトを必要とするロールを実装する必要があるため、likersandへの呼び出しが成功するという確信が持てます。do_like

于 2012-08-24T12:49:37.410 に答える