2010-10-20 57 views
6

使用Moose,是否可以創建一個可以一次構建多個屬性的構建器?如何使用Moose中的單個構建器構建多個屬性?

我有一個項目,其中的對象有幾個'集'的字段 - 如果該集的任何成員被請求,我想繼續並填充它們。我的假設是,如果我需要名稱,我還需要生日,並且由於它們在同一個表中,所以在一個查詢中獲得這兩個名稱會更快。

我不確定我的問題是否足夠清晰,但希望某些示例代碼能夠清楚說明。

我有什麼:

Package WidgetPerson; 
use Moose; 

has id => (is => 'ro', isa => 'Int'); 
has name => (is => 'ro', lazy => 1, builder => '_build_name'); 
has birthdate => (is => 'ro', lazy => 1, builder => '_build_birthdate'); 
has address => (is => 'ro', lazy => 1, builder => '_build_address'); 

sub _build_name { 
my $self = shift; 
my ($name) = $dbh->selectrow_array("SELECT name FROM people WHERE id = ?", {}, $self->id); 
return $name; 
} 
sub _build_birthdate { 
my $self = shift; 
my ($date) = $dbh->selectrow_array("SELECT birthdate FROM people WHERE id = ?", {}, $self->id); 
return $date; 
} 
sub _build_address { 
my $self = shift; 
my ($date) = $dbh->selectrow_array("SELECT address FROM addresses WHERE person_id = ?", {}, $self->id); 
return $date; 
} 

但我想要的是:

has name => (is => 'ro', isa => 'Str', lazy => 1, builder => '_build_stuff'); 
has birthdate => (is => 'ro', isa => 'Date', lazy => 1, builder => '_build_stuff'); 
has address => (is => 'ro', isa => 'Address', lazy => 1, builder => '_build_address'); 
sub _build_stuff { 
my $self = shift; 
my ($name, $date) = $dbh->selectrow_array("SELECT name, birthdate FROM people WHERE id = ?", {}, $self->id); 
$self->name($name); 
$self->birthdate($date); 
} 
sub _build_address { 
#same as before 
} 

回答

7

我在這種情況下做的,當我不希望有一個獨立的在以太的答案中的對象,對於中間狀態具有一種懶散的屬性。因此,舉例來說:

has raw_row => (is => 'ro', init_arg => undef, lazy => 1, builder => '_build_raw_row'); 
has birthdate => (is => 'ro', lazy => 1, builder => '_build_birthdate'); 

sub _build_raw_row { 
    $dbh->selectrow_hashref(...); 
} 

sub _build_birthdate { 
    my $self = shift; 
    return $self->raw_row->{birthdate}; 
} 

重複同樣的模式birthdate的名稱等

閱讀任何單個屬性將嘗試從raw_row獲取數據,它的懶惰建設者將只運行一次SQL 。由於您的屬性都是隻讀的,因此如果其中一個對象狀態發生更改,則不必擔心更新任何對象狀態。

此模式對於XML文檔等內容也很有用 - 您保存的中間狀態可以是例如一個DOM,每個屬性都是從XPath表達式或者什麼都可以構建的。

+0

好的模式,但如果有很多屬性,有沒有辦法避免重複:build =>'_build_attribute1'... sub _build_attribute1 {my $ self = shift;返回$ self-> raw_row - > {attribute1}; } 一遍又一遍地?也許有一種方法讓_build_attribute識別調用它的屬性? – yahermann 2017-03-18 05:00:45

+0

@yahermann,我認爲這個問題已經到了。如果你可以做你的建議,這個問題就不存在了。 – UncleCarl 2018-03-06 23:37:42

5

沒有,屬性建設者只能在同一時間返回一個值。您可以通過讓每個構建者在返回之前設置其他屬性的值來構建兩者,但這會很快變得很難看......

但是,如果您通常有兩段數據以某種方式結合例如,在同一數據庫的查詢來爲你的情況),你可以集中在一個屬性作爲一個對象存儲這些值:

has birth_info => (
    is => 'ro', isa => 'MyApp::Data::BirthInfo', 
    lazy => 1, 
    default => sub { 
     MyApp::Data::BirthInfo->new(shift->some_id) 
    }, 
    handles => [ qw(birthdate name) ], 
); 

package MyApp::Data::BirthInfo; 
use Moose; 
has some_id => (
    is => 'ro', isa => 'Int', 
    trigger => sub { 
     # perhaps this object self-populates from the DB when you assign its id? 
     # or use some other mechanism to load the row in an ORMish way (perhaps BUILD) 
    } 
); 
has birthdate => (
    is => 'ro', isa => 'Str', 
); 
has name => (
    is => 'ro', isa => 'Str', 
); 
+0

嗯。這可能會起作用,但它似乎增加了我試圖減少它的複雜性。 – RickF 2010-10-20 15:30:51

+0

@RickF:用一個構建器構建兩個屬性將比在單個對象上存儲兩個屬性更復雜。 – Ether 2010-10-20 16:20:20

+0

你可能是對的。我的猶豫很大程度上是由於腸道反應水平的阻力,以簡單的方式重現了駝鹿形式的複雜表格結構。 – RickF 2010-10-20 17:49:57

相關問題