2010-11-19 37 views
6

Tôi có một loạt các tính năng lười biếng trong một đối tượng Moose.Làm cách nào để tạo tất cả các tính năng của Moose lười biếng?

Một số nhà xây dựng yêu cầu thời gian để hoàn thành.

Tôi muốn nvoke tất cả các nhà xây dựng (kết xuất đối tượng "không đầy đủ"). Tôi có thể làm cho tất cả các tính năng lười biếng được xây dựng cùng một lúc hay tôi phải gọi từng tính năng theo cách thủ công để khiến trình xây dựng chạy?

+1

Bạn không nên sử dụng 'mặc định' cho điều đó? Tôi nghĩ rằng điểm 'lười biếng' là trì hoãn việc tạo giá trị thuộc tính cho đến lần sử dụng đầu tiên. Nếu bạn cần tất cả các thuộc tính được đặt ở cấu trúc đối tượng, 'mặc định' có vẻ hữu ích hơn. Hoặc, bạn có thể cung cấp phương thức 'BUILD' của riêng bạn. –

+0

Đây là một thành ngữ khá phổ biến và có một số lý do hợp lý cho nó. – hobbs

+0

Về cơ bản, bạn có thể làm tất cả công việc trong 'BUILD' thay vào đó, nhưng tốt hơn là nên có một phương thức cho mỗi thuộc tính. Và nếu bạn sẽ có một phương thức cho mỗi thuộc tính để tính giá trị thì nó cũng có thể là một người xây dựng. Nhưng nếu một người xây dựng sẽ truy cập các thuộc tính khác thì thuộc tính được xây dựng cần phải được lười biếng để chắc chắn rằng chúng đã được khởi tạo. Và không có tùy chọn thuộc tính "lười biếng, nhưng chỉ một chút * lười biếng" * – hobbs

Trả lời

6

Nếu bạn muốn có thuộc tính "lười" với người xây dựng, nhưng đảm bảo rằng giá trị của chúng được tạo trước khi trả về new, điều thông thường cần làm là gọi cho người truy cập theo số BUILD.

sub BUILD { 
    my ($self) = @_; 

    $self->foo; 
    $self->bar; 
} 

là đủ để hoàn thành công việc, nhưng tốt nhất bạn nên thêm nhận xét cũng như giải thích mã có vẻ vô dụng này cho người không biết thành ngữ.

3

Có thể bạn có thể sử dụng lớp meta để lấy danh sách thuộc tính 'lười'. Ví dụ:

package Test; 

use Moose; 


has ['attr1', 'attr2'] => (is => 'rw', lazy_build => 1); 
has ['attr3', 'attr4'] => (is => 'rw',); 

sub BUILD { 
    my $self = shift; 


    my $meta = $self->meta; 

     foreach my $attribute_name (sort $meta->get_attribute_list) { 

     my $attribute = $meta->get_attribute($attribute_name); 

     if ($attribute->has_builder) { 
      my $code = $self->can($attribute_name); 
      $self->$code; 

     } 
    } 

} 


    sub _build_attr1 { 1 } 
    sub _build_attr2 { 1 } 
2

Tôi đã có yêu cầu chính xác này nhiều lần trong quá khứ và hôm nay tôi thực sự phải làm điều đó từ metaclass, điều này có nghĩa là không cho phép chỉnh sửa BUILD. Dù sao tôi cảm thấy nó sẽ là tốt để chia sẻ vì nó về cơ bản thực hiện chính xác những gì ether đề cập:

'Nó sẽ cho phép đánh dấu các thuộc tính "này là lười biếng, vì nó phụ thuộc trên các giá trị thuộc tính khác được xây dựng, nhưng tôi muốn . nó được chọc trước khi kết thúc xây dựng "'

Tuy nhiên, derp derp tôi không có ý tưởng làm thế nào để tạo ra một mô-đun CPAN vì vậy đây là một số mã: https://gist.github.com/TiMBuS/5787018

Đặt trên vào Late.pm và sau đó bạn có thể sử dụng i t như vậy:

package Thing; 
use Moose; 
use Late; 

has 'foo' => (
    is  => 'ro', 
    default => sub {print "setting foo to 10\n"; 10}, 
); 

has 'bar' => (
    is  => 'ro', 
    default => sub {print 'late bar being set to ', $_[0]->foo*2, "\n"; $_[0]->foo*2}, 
    late => 1, 
); 

#If you want.. 
__PACKAGE__->meta->make_immutable; 
1; 


package main; 

Thing->new(); 
#`bar` will be initialized to 20 right now, and always after `foo`. 
#You can even set `foo` to 'lazy' or 'late' and it will still work. 
Các vấn đề liên quan