20

如果您有一个需要在设置时随时修改的属性,是否有一种巧妙的方法可以做到这一点,而不是自己编写访问器并直接处理 的内容$self,如本例中所做的那样?

package Foo;
use Moose;

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

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

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

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

4

4 回答 4

10

您可以使用方法修饰符“around”。像这样的东西:

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

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

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

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

于 2009-09-13T00:58:35.687 回答
8

我认为在这样的触发器中使用哈希引用很好:

package Foo;
use Moose;

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

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

回复:哈希引用 - 通常我认为最好坚持使用属性设置器/获取器,除非(如上面的触发器)没有简单的替代方案。

顺便说一句,您可能会发现这篇关于触发器的最新帖子没什么意思

于 2009-09-12T19:15:53.473 回答
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

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

于 2009-09-12T23:48:49.023 回答
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);
}

这或触发器会让我觉得这是一种好方法,具体取决于您需要何时以及如何操纵论点。

(免责声明:从内存中编写的未经测试的代码,在具有片状边缘访问的上网本上浏览 SO)

于 2009-09-12T23:38:03.633 回答