我有一个具有以下属性的Moose对象:
has 'people' => (
is => 'ro',
isa => 'ArrayRef[Person::Child]',
traits => ['Array'],
default => sub { [] },
handles => {
all_people => 'elements',
get_people => 'get',
push_people => 'push',
pop_people => 'pop',
count_people => 'count',
sort_people => 'sort',
grep_people => 'grep',
},
);
注意isa
设置为'ArrayRef [Person :: Child]'。
我希望能够在创建我的对象时在Person::Child
,Person::Adult
等之间进行选择。是否可以或者我必须创建除isa
属性的people
之外的相同对象?
(这让我想起了Java generics)。
答案 0 :(得分:5)
为什么不将该属性的定义移动到角色中并重新使用它 适当的参数化,在其他类别?
package MyApp::Thingy::HasPeople;
use MooseX::Role::Parameterized;
parameter person_type => (
isa => 'Str',
required => 1,
);
role {
my $person_type = shift->person_type;
has 'people' => (
is => 'ro',
isa => "ArrayRef[${person_type}]",
traits => ['Array'],
default => sub { [] },
handles => {
all_people => 'elements',
get_people => 'get',
push_people => 'push',
pop_people => 'pop',
count_people => 'count',
sort_people => 'sort',
grep_people => 'grep',
},
);
};
1;
以及其他地方,在实际需要该属性的类
中package MyApp::Thingy::WithChildren;
use Moose;
with 'MyApp::Thingy::HasPeople' => { person_type => 'Person::Child' };
1;
或
package MyApp::Thingy::WithAdults;
use Moose;
with 'MyApp::Thingy::HasPeople' => { person_type => 'Person::Adult' };
1;
这样你就不会在两个地方维护属性,也不会结束 使用相同类但具有不同API的对象,这往往是一个漂亮的 大码嗅觉。
或者,您可以简单地编写ArrayRef
的子类型,该子类型接受Person::Child
或Person::Adult
的列表或您拥有的任何其他类型的人,但只有所有人都可以该清单的元素属于同一类。
use List::AllUtils 'all';
subtype 'PersonList', as 'ArrayRef', where {
my $class = blessed $_->[0];
$_->[0]->isa('Person') && all { blessed $_ eq $class } @{ $_ };
};
has persons => (
is => 'ro',
isa => 'PersonList',
...,
);
我可能会选择第一个解决方案,以便能够根据对象类决定它是否包含儿童,成人或其他任何内容。
答案 1 :(得分:1)
如果你喜欢Java,你可能会喜欢这个:
package Interfaces::Person;
use Moose::Role;
requires qw( list all attributes or methods that you require );
1;
确认Person :: Adult和Person :: Child实现此接口:
package Person::Adult;
...
# add at the end
with qw(Interfaces::Person);
1;
和
package Person::Child;
...
# add at the end
with qw(Interfaces::Person);
1;
回到主班:
package My::People;
use Moose;
use MooseX::Types::Moose qw( ArrayRef );
use MooseX::Types::Implements qw( Implements );
has 'people' => (
is => 'ro',
isa => ArrayRef[Implements[qw(Interfaces::Person)]],
traits => ['Array'],
default => sub { [] },
handles => {
all_people => 'elements',
get_people => 'get',
push_people => 'push',
pop_people => 'pop',
count_people => 'count',
sort_people => 'sort',
grep_people => 'grep',
},
);
现在只有实现Interfaces :: Person接口的类才能添加到'people'。