使用 BUILDARGS 替换角色中的类



我使用Perl Moose Role(Import::Git::Role(作为抽象基类,以在实际实现功能的类(Import::Git(和执行一些日志记录的类(Import::Git::dryrun(之间共享共同的行为。

我希望干运行类是透明的。我想创建一个这样的对象:

my $git = Import::Git->new( dryrun => $dryrun );

变量 dryrun 可以是 0 或 1。如果它是 1,我想构造一个Import::Git::dryrun对象,基本上用它替换Import::Git对象。这是有意为之的,因为它们通过角色共享所有方法。

我尝试在 BUILDARGS 方法期间交换对象,如下所示:

around BUILDARGS => sub {                                                                                                                                                                                                                                                           
my $orig  = shift;
my $class = shift;
my %args = ( @_ == 1 ? %{ $_[ 0 ] } : @_ );
if ( !%args || $args{ 'dryrun' } != 1 ) {
return $class->$orig( @_ );
}
else {
return Import::Git::dryrun->$orig( @_ );
}
};

但这并没有实现我想要做的事情,它构建了旧类:

DB<1> x Import::Git->new( dryrun => 1 )
0  Import::Git=HASH(0x2fd9210)
'dryrun' => 1
DB<2> x Import::Git->new()
0  Import::Git=HASH(0x301dbb8)
'dryrun' => 0
DB<3> 

我想我可能不得不调用dryrun方法的新方法,所以我进行了以下交换:

# change this:
return Import::Git::dryrun->$orig( @_ );
# to this
return Import::Git::dryrun->new( @_ ); 

但它返回BUILDARGS did not return a HASH reference.

我错过了什么?

让构造函数构建一个与请求的类不同的类是令人讨厌的。即使它确实有效,我也不会采用您所做的方法。我会使用

sub factory {
my ($class, %opts) = @_;
return $opt{dryrun} ? $class.'::dryrun' : $class;
}
Import::Git->factory( dryrun => $dryrun )->new( ... )

sub instantiate {
my ($class, %opts) = @_;
return ( delete($opt{dryrun}) ? $class.'::dryrun' : $class )->new(%opts);
}
Import::Git->instantiate( dryrun => $dryrun, ... )
BUILDARGS

用于在创建对象之前操作传递给对象构造函数的参数列表,因此对新返回的内容没有影响。您可能不想尝试around BUILDARGSaround new,然后您可以将 new 返回的对象替换为您的 dry 运行对象。

最新更新