在Moose中,如何在设置属性时修改属性?

时间:2009-09-12 17:29:53

标签: perl moose

如果你有一个属性需要在设置的任何时候进行修改,有没有一种方法可以自己编写访问器并直接使用$self的内容进行修改,就像在这个例子?

package Foo;
use Moose;

has 'bar' => (
    isa => 'Str',
    reader => 'get_bar',
);

sub set_bar {
    my ($self, $bar) = @_;
    $self->{bar} = "modified: $bar";
}

我考虑过trigger,但似乎需要采用相同的方法。

直接使用$self中的哈希引用在[{3}}中被认为是不好的做法,还是我担心没有问题?

4 个答案:

答案 0 :(得分:10)

您可以使用方法修饰符'around'。像这样:

has 'bar' => (
    isa    => 'Str',
    reader => 'get_bar',
    writer => 'set_bar'
);

around 'set_bar' => sub {
    my ($next, $self, $bar) = @_;
    $self->$next( "Modified: $bar" );
};

是的,直接使用哈希值被认为是不好的做法。

另外,请不要认为我提出的选项必然是正确的。在大多数情况下使用子类型和强制将是正确的解决方案 - 如果您根据可能在整个应用程序中重用的类型来考虑您的参数将导致更好的设计,即可以进行任意修改使用'around'完成。请参阅@daotoad的回答。

答案 1 :(得分:8)

我不确定您需要哪种修改,但您可以通过使用类型强制来实现所需的修改:

package Foo;
use Moose;

use Moose::Util::TypeConstraints;

subtype 'ModStr' 
    => as 'Str'
    => where { /^modified: /};

coerce 'ModStr'
    => from 'Str'
    => via { "modified: $_" };

has 'bar' => ( 
    isa => 'ModStr', 
    is  => 'rw', 
    coerce => 1,
);

如果使用此方法,则不会修改所有值。任何将验证作为ModStr传递的内容都将直接使用:

my $f = Foo->new();
$f->bar('modified: bar');  # Set without modification

这种弱点可能没问题,也可能使这种方法无法使用。在适当的情况下,它甚至可能是一个优势。

答案 2 :(得分:6)

我认为在trigger范围内使用哈希引用就好了:

package Foo;
use Moose;

has 'bar' => ( 
    isa => 'Str', 
    is  => 'rw', 
    trigger => sub { $_[0]->{bar} = "modified: $_[1]" },
);

bar arg与构造函数一起传递时,触发器也会触发。如果您定义自己的set_bar方法或使用方法修饰符,则不会发生这种情况。

re:哈希引用 - 通常我认为最好坚持使用属性setter / getters,除非(与上面的触发器一样)没有简单的替代方法。

顺便说一下,recent post about triggers感兴趣的是nothingmuch

答案 3 :(得分:3)

如果直接处理哈希导致你担心,你可以指定一个替代编写器,然后在你自己适当命名的“公共”编写器中使用它。

package Foo;
use Moose;

has 'bar' => (
   isa => 'Str',
   reader => 'get_bar',
   writer => '_set_bar',
);

sub set_bar {
   my $self = shift;
   my @args = @_;
   # play with args;
   return $self->_set_bar(@args);
}

这个或触发器会让我觉得这是一个很好的方法,取决于你何时以及如何操纵参数。

(免责声明:未经测试的代码从内存中写入,在具有不稳定边缘访问权限的上网本上浏览)