2011-01-31 55 views
4

假設我有多個角色,每一個定義一組項目:Perl類的屬性組成?

package A; 
use Moose::Role; 
sub items() { qw/apple orange/ } 

package B; 
use Moose::Role; 
with 'A'; 
sub items() { qw/watermelon/ } 

package C; 
use Moose::Role; 
sub items() { qw/banana/ } 

假設我在另一個類使用它們,我想收集所有這些項目:

package Foo; 
use Moose; 
with qw(B C); 

sub do_something { 
    my $self = shift; 
    my @items = ???; # How can I get apple, orange, watermelon, banana here? 
    .... 
} 

一個可能的解決方案是採用MooseX::ComposedBehavior,但其POD表示(當然,在撰寫本文時)其API「不太穩定」,並且「目前的實現有點破綻,應該由更強大的代替」。因此,我正在調查這是否可以在不依賴這種「黑客」的情況下完成。

警告:如果你在未來讀這篇文章,請去檢查MooseX::ComposedBehavior(當前版本:0.003)的POD,因爲它可能會在此期間發生了變化。事情變化很快。 CPAN作者發佈新版本。目前的「不太穩定」可能在未來變得更加穩定。甚至可能還有其他模塊。自行檢查。

理想情況下,應該是這樣的:my @items = map $_->items, @ISA; 但是,這將不適用於穆斯。有沒有更好的和更可靠的解決方案?


更新:我結束了本三線的解決方案:

package A; 
use Moose::Role; 
sub items() { qw/apple orange/ } 

package B; 
use Moose::Role; 
with 'A'; 
sub items() { qw/watermelon/ } 

package C; 
use Moose::Role; 
sub items() { qw/banana/ } 

package Foo; 
use Moose; 
with qw(B C); 
sub items() {} 

sub do_something { 
    my $self = shift; 

    my @items = map $_->execute, grep $_, 
     map $_->get_method('items'), 
     $self->meta->calculate_all_roles_with_inheritance; 

    ... 
} 

更新:由於不同的人要求我在#moose IRC channel我打消了我之前的說法,MooseX :: ComposedBehavior「不穩定」,並將其替換爲從其POD中獲取的文本文本。


更新:我寫了一個MooseX::Collect模塊允許的語法如下:

package Foo; 
use Moose; 
use MooseX::Collect; 

collect 'items'; 
with qw(B C); 

sub do_something { 
    my $self = shift; 
    my @items = $self->items; 
    ... 
} 
+3

我不認爲你想在這裏擔任角色。當你在Foo中編寫「B」和「C」角色時,你會與「items」方法產生衝突,不僅Foo不會編譯,而且編譯的過程也是創建你自己的「items 「 方法。 – 2011-01-31 14:41:27

回答

7

您需要使用around

package A; 
use Moose::Role; 
requires 'items'; 
around items => sub { 
    my ($orig, $self, @args) = @_; 
    return ($self->$orig(@args), qw/apple orange/); 
}; 

package B; 
use Moose::Role; 
requires 'items'; 
with 'A'; # not required, do it if you want it 
around items => sub { 
    my ($orig, $self, @args) = @_; 
    return ($self->$orig(@args), qw/watermelon/); 
}; 

package C; 
use Moose::Role; 
requires 'items'; 
around items => sub { 
    my ($orig, $self, @args) = @_; 
    return ($self->$orig(@args), qw/banana/); 
}; 

package Class; 
use Moose; 
with qw/B C/; 
sub items {} 

但在一般情況下,使用類來表示數據是錯誤的,那是什麼 實例 o f類是爲了。因爲你的例子非常瑣碎,所以很難提供進一步的建議。你真的想做什麼?

+0

我想過使用`override items => sub {return super(),qw(banana)};`。我的角色將描述應用程序功能,並且每個角色定義一個將應用於應用程序配置的`Data :: Schema`驗證模式。 – Alessandro 2011-01-31 12:51:36

+0

使用`around`的另一種方法可能會包裝BUILDARGS,修改初始輸入一次(提供我是否可以影響BUILDARGS的角色)。 – Carl 2011-01-31 14:26:59

5

在IRC上指向MooseX::ComposedBehavior之前,我不完全確定爲什麼你覺得你不應該使用它。畢竟,它確實解決了你遇到的問題。

是的,它確實表示它的接口將來可能會稍微改變。但是,爲了適應這些微小的變化,你需要做多少工作?相比之下,您認爲您需要多長時間才能提出替代解決方案並實際實施?您認爲您的解決方案與MooseX::ComposedBehavior相比,在正確性和穩健性方面如何?至少我不會相信自己在重塑最初由RJBS發明的輪子,並期望我的解決方案更好。另外,如果你真的超級擔心模塊會警告你未來可能發生的變化,請與作者一起工作,並幫助他將其變爲一種令他滿意的形狀,以便將其聲明爲穩定。爲你的特定用例寫更多的測試。和裏卡多交談,他是個好人。