通过调用包装对象创建属性默认值
Creating attribute defaults by calling a wrapped object
我有一个包含 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
但这似乎是一个 hack。
有谁知道我如何完成这种属性声明样式,或者是否需要分别声明每个属性及其默认值?
您可以在问号所在的位置使用 $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 };
}
这可能通过内部对象中的方法委托和默认值来更好地处理。
有了这些,你举的例子可以更好的写成:
#!/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 中添加到包装的 'handles' 数组引用以指示应将其委托给该对象。
如果不希望将默认值应用于 InnerClass 的所有实例,则可以从那里删除默认值,指定所有必需的属性(以提供更好的错误检测),并在默认构造函数中指定所有属性.
我有一个包含 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
但这似乎是一个 hack。
有谁知道我如何完成这种属性声明样式,或者是否需要分别声明每个属性及其默认值?
您可以在问号所在的位置使用 $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 };
}
这可能通过内部对象中的方法委托和默认值来更好地处理。
有了这些,你举的例子可以更好的写成:
#!/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 中添加到包装的 'handles' 数组引用以指示应将其委托给该对象。
如果不希望将默认值应用于 InnerClass 的所有实例,则可以从那里删除默认值,指定所有必需的属性(以提供更好的错误检测),并在默认构造函数中指定所有属性.