我有一个将InnerClass对象作为属性的WrapperClass对象。 InnerClass对象具有权重属性。我的WrapperClass对象也有一个权重属性,我希望它的默认值是InnerClass对象的权重属性的值。
#!/usr/bin/perl
package InnerClass;
use Moose;
has 'weight' => (
is => 'rw',
);
package WrapperClass;
use Moose;
has 'wrapped' => (
is => 'rw',
lazy => 1,
default => sub {InnerClass->new(weight => 1)},
);
has 'weight' => (
is => 'rw',
default => sub {
my $self = shift;
$self->wrapped->weight()
},
lazy => 1,
);
上面的代码有效,但实际上,InnerClass有很多属性,WrapperClass需要做同样的事情。理想情况下,当我写WrapperClass时,我会做这样的事情:
use Moose;
has 'wrapped' => (
is => 'rw',
);
my @getDefaultsFromWrappers
= qw(weight height mass x y z label); # etc ...
foreach my $attr (@getDefaultsFromWrappers) {
has $attr => (
is => 'rw',
default => sub {
# Somehow tell the default which attribute
# it needs to call from wrapped object?
my $self = shift;
$self->wrapped->???()
},
lazy => 1,
);
}
但是,无法将参数传递给默认值或构建器以告知它正在构建哪个属性。我考虑过使用caller
,但这看起来像是一个黑客。
有谁知道如何完成这种属性声明的方式,还是分别声明每个属性及其默认值?
答案 0 :(得分:1)
您可以在问号所在地使用$attr
,因为在声明属性时它仍在范围内。
foreach my $attr (@getDefaultsFromWrappers) {
has $attr => (
is => 'rw',
default => sub { shift->wrapped->$attr() },
lazy => 1,
);
}
以下是一种可能的替代方法,如果属性声明不统一,您可能需要使用以下选项:
has weight => (
is => 'rw',
isa => 'Num',
default => _build_default_sub('weight'),
lazy => 1,
);
has label => (
is => 'rw',
isa => 'Str',
default => _build_default_sub('label'),
lazy => 1,
);
sub _build_default_sub {
my ($attr) = @_;
return sub { shift->wrapped->$attr };
}
答案 1 :(得分:0)
这可以通过内部对象中的方法委派和默认值来更好地处理。
有了这些,您给出的示例可以更好地写为:
#!/usr/bin/perl
use strict;
use warnings;
package InnerClass;
use Moose;
has weight => (
is => 'rw',
default => 1,
);
package WrapperClass;
use Moose;
has wrapped => (
is => 'rw',
isa => 'InnerClass',
lazy => 1,
default => sub { InnerClass->new },
handles => [ 'weight' ],
);
package main;
my $foo = WrapperClass->new;
print $foo->weight;
任何其他默认值都将作为默认值添加到InnerClass上,并且在WrapperClass中,添加到包装的'句柄'数组引用表明它应该委托给该对象。
如果不希望将默认值应用于InnerClass的所有实例,则可以从那里删除默认值,指定所需的所有属性(以提供更好的错误检测),并在默认构造函数中指定所有属性