2015-06-11 2 views
0

У меня есть объект WrapperClass, который имеет объект InnerClass как атрибут. Объект 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, но это похоже на взлом.

Кто-нибудь знает, как я мог выполнить этот стиль объявления атрибута, или это случай объявления каждого атрибута и его значения по умолчанию отдельно?

ответ

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 }; 
} 
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, вы можете удалить по умолчанию оттуда, указать все необходимые атрибуты (чтобы обеспечить лучшее обнаружение ошибок) и указать все атрибуты в конструкторе по умолчанию.

 Смежные вопросы

  • Нет связанных вопросов^_^