我有一个基类和十几个派生类.除一个派生类之外的所有类都需要名为key的属性.所以我可以将它添加到11个派生类中,并将第12个单独留下.
但是,懒惰就是这样,我想将属性添加到基类中,从而避免重复声明十一次并添加我认为的一致性和简单性.
现在,这对于不需要key属性的一个类造成了问题.请注意,如果此类具有此属性,则不会有任何损害,但它不需要它.
我的想法是通过使用标志方法is_strict解决这个问题,该方法将从BUILDARGS调用以决定是否需要密钥.这是一个简单的脚本来说明这一点(好吧,我颠倒了这个概念,只有一个案例需要关键属性(而不是除了一个案例之外的所有案例),但问题仍然受到这种反转的影响):
#!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 package Bla; use Moose; use Carp (); has grop => 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的包租性比其他语言的对象系统要差.
啊,我已经看到你应该为你用a重写的属性定义作为前缀,所以如果在父类中找不到引用的属性,Moose会可怜地呱呱叫,为你的代码增加了安全性和一致性.我相应地更新了我的示例代码.