2009-09-12 19 views
18

Nếu bạn có một thuộc tính cần phải sửa đổi bất kỳ lúc nào được thiết lập, có cách nào ngắn gọn để viết ngắn dòng này và tự động mút trực tiếp với nội dung của $self, như được làm trong ví dụ này?Trong Moose, làm thế nào để sửa đổi một thuộc tính bất cứ lúc nào nó được thiết lập?

package Foo; 
use Moose; 

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

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

Tôi xem là trigger, nhưng dường như yêu cầu cùng một cách tiếp cận.

Đang làm việc trực tiếp với tham chiếu băm trong $self được coi là thực hành không tốt trong Moose hoặc tôi lo lắng về sự cố không?

Trả lời

8

Tôi không chắc chắn những loại thay đổi bạn cần, nhưng bạn có thể có thể đạt được những gì bạn cần bằng cách sử dụng loại cưỡng chế:

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, 
); 

Nếu bạn sử dụng cách tiếp cận này, không phải tất cả giá trị đều sẽ được sửa đổi. Bất kỳ điều gì vượt qua xác thực là ModStr sẽ được sử dụng trực tiếp:

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

Điểm yếu này có thể được chấp nhận hoặc có thể làm cho phương pháp này không thể sử dụng được. Trong hoàn cảnh thích hợp, nó thậm chí có thể là một lợi thế.

6

Tôi nghĩ rằng bằng cách sử dụng tài liệu tham khảo băm là tốt trong một trigger như thế này:

package Foo; 
use Moose; 

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

Các kích hoạt cũng bắn khi thanh arg thông qua với các nhà xây dựng. Điều này sẽ không xảy ra nếu bạn định nghĩa phương thức set_bar của riêng mình hoặc với một công cụ sửa đổi phương thức.

lại: tham chiếu băm - Nói chung, tôi nghĩ tốt nhất nên gắn với trình định vị thuộc tính/getters trừ khi (như với trình kích hoạt ở trên) không có cách thay thế dễ dàng.

BTW bạn có thể tìm thấy điều này recent post about triggers bởi nothingmuch thú vị.

+0

Xem Moose :: Hướng dẫn :: Thuộc tính trên trình kích hoạt - http://search.cpan.org/~drolsky/Moose-0.88/lib/Moose/Manual/Attributes.pod#Triggers –

3

Nếu giao dịch trực tiếp với hàm băm khiến bạn lo ngại, bạn có thể chỉ định một nhà văn thay thế và sau đó sử dụng nó từ bên trong một nhà văn 'công khai' được đặt tên thích hợp.

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); 
} 

Điều này, hoặc trình kích hoạt, sẽ đánh tôi như một cách tiếp cận tốt tùy thuộc vào thời điểm và cách thức bạn cần thao tác đối số.

(từ chối trách nhiệm: Mã chưa được kiểm tra bằng văn bản từ bộ nhớ, duyệt SO trên một netbook với truy cập cạnh ổn định?)

+0

Đây là một công cụ đẹp giải pháp mặc dù nó sẽ không hoạt động với các nhà xây dựng. – mikegrb

+0

@mikegrb: Tôi không chắc chính xác bạn muốn làm gì với các nhà xây dựng, nhưng bạn có thể chỉ rõ nơi một giá trị được gán thông qua một hàm tạo bằng cách sử dụng công cụ sửa đổi thuộc tính 'init_arg' và/hoặc bạn có thể thực hiện một số kiểm tra trong' BUILDARGS 'phương thức. – Ether

9

Bạn có thể sử dụng công cụ sửa đổi phương thức 'xung quanh'. Một cái gì đó như thế này:

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

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

Và có, làm việc trực tiếp với giá trị băm được coi là hành vi xấu.

Ngoài ra, vui lòng không giả định rằng tùy chọn tôi đã trình bày nhất thiết phải là tùy chọn phù hợp. Việc sử dụng các kiểu con và ép buộc sẽ là giải pháp phù hợp nhất - nếu bạn nghĩ về tham số của mình dưới dạng một loại có thể được sử dụng lại trong toàn bộ ứng dụng của bạn sẽ dẫn đến thiết kế tốt hơn nhiều. thực hiện bằng cách sử dụng 'xung quanh'. Xem câu trả lời từ @daotoad.

+1

Để làm việc này, bạn cần phải khai báo một người viết khi xác định thuộc tính. Ví dụ, có 'bar' => (là => 'rw', isa => 'Str', writer => 'set_bar') – draegtun

+0

re: giá trị băm "thực hành xấu": tốt của nó trong các tác nhân và ví dụ tôi đã nhìn thấy (trên danh sách gửi thư Moose) làm tái khẳng định điều này. – draegtun

+0

draegtun: trừ khi Moose thay đổi nó, người viết mặc định là tên thuộc tính. Bạn có thể đặt xung quanh vào đó nếu bạn không muốn chỉ định người viết. –

Các vấn đề liên quan