Perl中对象构造函数中命名参数的习惯用法

Red*_*ick 1 oop parameters perl idioms

在Perl中,如果我想在对象构造函数中使用命名参数,如果我希望进行一些验证,我的代码似乎有点笨拙.

sub new {

   my $class = shift;
   my $self = {};

   my %args = @_;
   foreach my $argname (keys %args) {
     if    ($argname eq 'FOO') { $self->{$argname} = $args{$argname}; }
     elsif ($argname eq 'BAR') { $self->{$argname} = $args{$argname}; }
     elsif ($argname eq 'BAZ') { $self->{$argname} = $args{$argname}; }
     …
     else                      { die "illegal argument $argname\n"; }
   }

   bless $self;
   return $self;
}
Run Code Online (Sandbox Code Playgroud)

首先,有一个临时的hash(%args)似乎有点笨拙.其次,整个if链条似乎冗长乏味.

后者可以简化为

  if ('-FOO-BAR-BAZ-'=~m/-$argname-/) { $self->{$argname} = $args{$argname} }
  else { die "..."; }
Run Code Online (Sandbox Code Playgroud)

但我想这可以改进.

如果我需要检查值,if … elsif链仍然是必要的吗?

我搜索了一下但找不到更好的成语.有没有(除了使用某种Perl OO框架)

Seb*_*mpf 8

我发现自己不断编写不必要的代码来检查给定的参数.但后来我发现了Params :: Validate.它易于使用,如果验证失败,它提供非常清晰和用户友好的错误消息.涵盖所有可能的参数组合及其错误消息是一项繁琐的工作.我更喜欢这种方式:

use Params::Validate qw/:all/;
sub new {
    my $pkg = shift;
    validate(
        @_, {
            foo => { type => SCALAR | ARRAYREF },
            bar => { type => SCALAR, optional => 1},
            baz => { type => ARRAYREF, default => ['value'] },
            quux => { isa => 'CGI' }
        }
    );

    return bless { @_ }, $pkg;
}
Run Code Online (Sandbox Code Playgroud)

后来这段代码

MyApp::Something->new(
    foo => 123,
    bbr => 'typo',
    quux => CGI->new()
);
Run Code Online (Sandbox Code Playgroud)

变为:

The following parameter was passed in the call to MyApp::Something::new but was not listed in the validation options: bbr
 at test.pl line 14.
    MyApp::Something::new(undef, 'foo', 123, 'bbr', 'typo', 'quux', 'CGI=HASH(0x7fd4fa1857e0)') called at test.pl line 27
Run Code Online (Sandbox Code Playgroud)