我有一個Moose對象模塊,它應該接受一個相對較大的數據結構(ds
)作爲其構造函數參數之一。它用來計算一些對象的屬性。但是,我不希望將ds
本身存儲爲屬性 - 僅在構建對象時才需要它。我如何需要一個不是屬性的Moose構造函數arg?
我想過使用BUILDARGS
但我不確定如何定義ds
是必需的參數。
我該如何解決這個問題?
我有一個Moose對象模塊,它應該接受一個相對較大的數據結構(ds
)作爲其構造函數參數之一。它用來計算一些對象的屬性。但是,我不希望將ds
本身存儲爲屬性 - 僅在構建對象時才需要它。我如何需要一個不是屬性的Moose構造函數arg?
我想過使用BUILDARGS
但我不確定如何定義ds
是必需的參數。
我該如何解決這個問題?
我會傾向於有一個構造函數,只採用從您的數據結構派生的計算值。然後使用不同的方法將有限參數加上數據結構作爲參數。
sub generate_foo_from_ds {
my $class = shift;
my %arg = @_;
my $ds = $arg{foo_data};
# Get attributes from args
my %attrib;
for (qw(foo bar baz) {
croak "Attrib '$_' is required" unless exists $arg{$_};
$attrib{$_} = $arg{$_};
}
# calculate some more attributes here.
$attrib{griz} = $ds->{whee} * $ds->{whoosh}/$ds->{whiz}[12];
my $foo = $class->new(%attrib);
return $foo;
}
然後讓你的對象,像這樣:
my $foo = Foo->generate_foo_from_ds(foo_data => $bar, foo => 1, bar => 2, baz => 2);
現在,您不必擔心奇怪的序列化問題或BUILDARGS甚至建立。你有一個簡單的方法,就是這樣。
您可以使用BUILD
或BUILDARGS
。很難說如果不知道更多關於你想要做什麼的情況會更好,但我猜BUILD
會是更好的選擇。
sub BUILD {
my $self = shift;
my $args = shift;
my $ds = $args->{ds} or confess "Argument (ds) is required";
$self->some_attr($ds->{...});
$self->other_attr($ds->{foo}[3]);
...
} # end BUILD
如果您希望穆斯檢查類型並確保其存在,則必須將其作爲屬性。但是你可以在使用它之後在BUILD
方法中清除它。
has 'ds' => (
is => 'ro',
isa => 'SomeType',
required => 1,
clearer => '_clear_ds',
);
sub BUILD {
my $self = shift;
my $args = shift;
my $ds = $self->ds;
$self->_clear_ds;
$self->some_attr($ds->{...});
$self->other_attr($ds->{foo}[3]);
...
} # end BUILD
你能說出讀者法別的東西(如_ds
)如果你想。
這樣我必須(a)手動檢查所需的參數是否確實給出(如您所做的那樣),並且(b)手動驗證arg的類型是否正確。這是我在穆斯很喜歡的兩件事。我也不能在這種情況下使用穆斯特的優勢嗎? – 2010-10-26 07:52:41
+1謝謝cjm。這些對象的序列化(使用KiokuDB)如何?當對象被加載時,不會執行'BUILD'並導致麻煩? – 2010-10-26 08:43:43
是的,駝鳥對象在進行了反序列化/解凍時,要經過標準的實例化步驟。幾個星期前進入這個。在我頭頂,可以將hasBeenInsantiated等屬性設置爲1,並在使用該數據計算其他屬性之前檢查它是否已傳遞到BUILD。 – wprl 2010-10-26 15:12:02
這是一個不錯的解決方案。現在,如果只有我的同事們會放棄對班級方法的不安。 – wprl 2010-10-26 15:14:50
類方法沒有錯。尤其是那些創建類的實例。 'generate_foo_from_ds'只是一個特殊用途的構造函數。順便說一句,我沒有注意到我的代碼中有一個錯誤,現在我已經修復了。我責怪咖啡因不足。 – daotoad 2010-10-26 16:23:04