如何在运行时将现有的 Moose 角色组合成一个类?

发布于 2024-09-04 15:04:09 字数 593 浏览 3 评论 0原文

假设我定义了一个抽象 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')

这会执行我的操作吗想要还是我完全走错了路?

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

Say I define an abstract My::Object and concrete role implementations My::Object::TypeA and My::Object::TypeB. For maintainability reasons, I'd like to not have a hardcoded table that looks at the object type and applies roles. As a DWIMmy example, I'm looking for something along these lines in 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);
}

Letting me get a My::Object with My::Object::TypeB role applied by doing the following:

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

Is this going to do what I want or am I on the entirely wrong track?

Edit: I simplified this too much; I don't want to have to know the type when I instantiate the object, I want the object to determine its type and apply the correct role's methods appropriately. I've edited my question to make this clearer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

节枝 2024-09-11 15:04:09

你尝试过吗?

$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');

Have you tried it?

$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'

Yields:

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

This appears to be what you want. Cleaned up the code in the oose.pm call is:

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');
姐不稀罕 2024-09-11 15:04:09

使用 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();

Use MooseX::Traits, it will turn your role into a trait that can be applied at runtime, then you just call:

   # 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();
单身情人 2024-09-11 15:04:09

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

package Class;
use Moose;

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

另外,您可以使用 perl 常量 __PACKAGE__ 来引用当前包。

After the question update I'll give it another crack: with() is just a function call.

package Class;
use Moose;

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

Also, you can reference the current package with the perl constant __PACKAGE__.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文