【问题标题】:Moose: override `required`ness of attribute in derived classMoose:覆盖派生类中属性的“必需”性
【发布时间】:2011-06-03 13:41:24
【问题描述】:

我有一个基类和十几个派生类。除一个派生类外,所有派生类都需要一个名为key 的属性。所以我可以将它添加到 11 个派生类中,而将第 12 个单独保留。

但是,懒惰就是这样,我想将属性添加到基类中,从而避免重复声明 11 次,并添加我认为的一致性和简单性。

现在,这对不需要 key 属性的一类造成了问题。请注意,如果这个类这个属性并没有什么坏处,但它并不需要它。

我的想法是通过使用标志方法is_strict 来解决此问题,该方法将从BUILDARGS 调用以决定是否需要key。这是一个简单的脚本来说明这一点(好吧,我颠倒了这个概念,key 属性仅在一种情况下需要(而不是在所有情况下都需要),但问题仍然受到这种颠倒的影响):

#!perl
package Bla;
use Moose;
use Carp ();
has grop => is => 'ro', isa => 'Str'; # optional
has key  => is => 'ro', isa => 'Int'; # required in all but one cases
# required => should depend on $class->is_strict;
sub is_strict { 0 } # not strict by default as per this base class
# imagine a bunch of other stuff here shared by all derived classes
around BUILDARGS => sub {
    my $orig = shift;
    my $class = shift;
    my $args = @_ == 1 ? shift : { @_ };
    Carp::croak 'key missing'
        if not exists $args->{key}
        and $class->is_strict;
    return $class->$orig( @_ );
};
no Moose; __PACKAGE__->meta->make_immutable;

package Bla::Eins;
use Moose; extends 'Bla';
no Moose; __PACKAGE__->meta->make_immutable;

package Bla::Zwei;
use Moose; extends 'Bla';
no Moose; __PACKAGE__->meta->make_immutable;

package Bla::Drei;
use Moose; extends 'Bla';
override is_strict => sub { 1 }; # but here it is required
no Moose; __PACKAGE__->meta->make_immutable;

package main;
use Test::More;
use Test::Exception;
lives_ok  { Bla::Eins->new };
lives_ok  { Bla::Zwei->new };
throws_ok { Bla::Drei->new } qr/key missing/;
lives_ok  { Bla::Drei->new( key => 99 ) };
done_testing;

这可行,但有没有更好的方法来实现我想要的?

【问题讨论】:

    标签: perl moose


    【解决方案1】:

    好吧,我有点笨,因为没有尝试最明显的解决方案,只需覆盖派生类中requiredness 与默认值不同的属性定义。我们开始:

    #!perl
    package Bla;
    use Moose;
    use Carp ();
    has grop => is => 'ro', isa => 'Str'; # optional
    has key  => is => 'ro', isa => 'Int'; # required in all but one cases
    # imagine a bunch of other stuff here shared by all derived classes
    no Moose; __PACKAGE__->meta->make_immutable;
    
    package Bla::Eins;
    use Moose; extends 'Bla';
    no Moose; __PACKAGE__->meta->make_immutable;
    
    package Bla::Zwei;
    use Moose; extends 'Bla';
    no Moose; __PACKAGE__->meta->make_immutable;
    
    package Bla::Drei;
    use Moose; extends 'Bla';
    # prefix an attribute you're overriding with a "+" sign
    has '+key' => is => 'ro', isa => 'Int', required => 1;
    no Moose; __PACKAGE__->meta->make_immutable;
    
    package main;
    use Test::More;
    use Test::Exception;
    lives_ok  { Bla::Eins->new };
    lives_ok  { Bla::Zwei->new };
    throws_ok { Bla::Drei->new } qr/\bkey\b.*\brequired\b/;
    lives_ok  { Bla::Drei->new( key => 99 ) };
    done_testing;
    

    不过,我仍然感谢所有反馈,因为这个 Mooseland 的特许权不如其他语言的对象系统。

    啊,我看到你应该在一个属性定义前面加上+,所以如果在父类中找不到引用的属性,Moose 会可怜地croak,为您的代码增加安全性和一致性。我已经相应地更新了我的示例代码。

    【讨论】:

    • “+key”也会从属性中复制其他特征,因此您只需要指定增量,即:has '+key' => ( required => 1 );
    【解决方案2】:

    除了使用has '+key' => (requires => 1),您可以将requires=> 1 放在原件中并使用has '+key' => (requires => 0) 将其关闭。在最初的请求中,有 11 个是必需的,只有一个不是必需的,这意味着只有一个定义需要覆盖,而其他 11 个可以保持不变。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-31
      • 2021-08-31
      • 1970-01-01
      • 1970-01-01
      • 2017-07-05
      • 2012-06-02
      • 2013-06-25
      • 1970-01-01
      相关资源
      最近更新 更多