使用BUILDARGS替换Role中的类

时间:2018-09-19 09:49:50

标签: perl moose

我使用Perl Moose角色(Import::Git::Role)作为抽象基类,以在类和功能的实际实现(Import::Git)与执行某些日志记录的类({ {1}})。

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

Import::Git::dryrun

变量dryrun可以为0或1。如果为1,我想构造一个 my $git = Import::Git->new( dryrun => $dryrun ); 对象,基本上用它替换Import::Git::dryrun对象。那是因为他们通过角色共享所有方法。

我曾尝试在BUILDARGS方法期间像这样交换对象:

Import::Git

但是这并没有达到我想要的目的,它构造了旧的类:

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( @_ );
    }
};

我以为我可能必须调用dryrun方法的新方法,所以我进行了以下交换:

  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> 

但是它返回 # change this: return Import::Git::dryrun->$orig( @_ ); # to this return Import::Git::dryrun->new( @_ );

我想念什么?

2 个答案:

答案 0 :(得分:2)

让构造函数构建一个与所请求的类不同的类很麻烦。即使它奏效,我也不会采用您采用的方法。我会用

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, ... )

答案 1 :(得分:1)

BUILDARGS用于处理在创建对象之前传递给对象构造函数的参数列表,因此不会影响新的返回值。您可以尝试使用around BUILDARGS来代替around new,然后用空运行对象替换new返回的对象。