【问题标题】:Creating attribute defaults by calling a wrapped object通过调用包装对象创建属性默认值
【发布时间】:2015-06-11 21:58:00
【问题描述】:

我有一个带有 InnerClass 对象作为属性的 WrapperClass 对象。 InnerClass 对象有一个权重属性。我的 WrapperClass 对象也有一个 weight 属性,我希望它的默认值是 InnerClass 对象的 weight 属性的值。

#!/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,但这似乎是一种黑客攻击。

有谁知道我怎样才能完成这种属性声明风格,还是单独声明每个属性及其默认值?

【问题讨论】:

    标签: perl oop moose


    【解决方案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 };
    }
    

    【讨论】:

      【解决方案2】:

      这可能会更好地通过内部对象中的方法委托和默认值来处理。

      有了这些,你给出的例子可以更好地写成:

      #!/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”数组 ref 以指示它应该委托给该对象。

      如果不希望将默认值应用于 InnerClass 的所有实例,则可以从那里删除默认值,指定所需的所有属性(以提供更好的错误检测),并在默认构造函数中指定所有属性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-15
        • 1970-01-01
        • 1970-01-01
        • 2012-07-11
        • 2020-04-09
        • 1970-01-01
        相关资源
        最近更新 更多