6

假设我定义了一个抽象的 My::Object 和具体的角色实现 My::Object::TypeA 和 My::Object::TypeB。出于可维护性的原因,我不希望有一个查看对象类型并应用角色的硬编码表。作为一个 DWIMmy 示例,我正在 My::Object 中寻找类似的内容:

has => 'id' (isa => 'Str', required => 1);

sub BUILD {
  my $self = shift;

  my $type = $self->lookup_type(); ## Returns 'TypeB'
  {"My::Object::$type"}->meta->apply($self);
}

通过执行以下操作,让我获得一个带有 My::Object::TypeB 角色的 My::Object:

my $obj = My::Object(id = 'foo')

这会做我想做的事还是我走错了路?

编辑:我简化了太多;我不想在实例化对象时知道类型,我希望对象确定其类型并适当地应用正确的角色方法。我已经编辑了我的问题以使其更清楚。

4

3 回答 3

7

你试过了吗?

$perl -Moose -E'
     sub BUILD { my ($self, $p) = @_; my $role = qq[Class::$$p{role}]; $role->meta->apply($self) };
     package Class::A; use Moose::Role; has a => (is => q[ro], default => 1);
     package main; say Class->new(role => q[A])->dump'

产量:

$VAR1 = bless( {
             'a' => 1
           }, 'Class::MOP::Class::__ANON__::SERIAL::1' );

这似乎是你想要的。清理 oose.pm 调用中的代码是:

package Class; 
use Moose;
sub BUILD { 
    my ($self, $p) = @_;
    my $role = qq[Class::$$p{role}];
    $role->meta->apply($self);
}

package Class::A;
use Moose::Role;

has a => ( is => 'ro', default => 1 );

package main;
Class->new(role => 'A');
于 2010-06-08T20:19:58.937 回答
4

使用MooseX::Traits,它会将你的角色变成可以在运行时应用的特征,然后你只需调用:

   # Where Class is a class that has `use MooseX::Traits`;
   # And TypeB is a simple role
   Class->new_with_traits( traits => [qw/TypeB/] )

   # or even the new, and now preferred method.
   Class->with_traits('TypeB')->new();
于 2010-06-08T19:54:44.597 回答
1

问题更新后,我再给它一个破解:with()只是一个函数调用。

package Class;
use Moose;

BEGIN {
  with ( map "MyObject::$_", qw/TypeA TypeB/ );
}

此外,您可以使用 perl 常量引用当前包__PACKAGE__

于 2010-06-08T20:16:12.347 回答