我有一个基类和十几个派生类。除一个派生类之外的所有类都需要名为key
的属性。所以我可以将它添加到11个派生类中,并将第12个单独留下。
然而,懒惰就是它,我想将该属性添加到基类中,从而避免重复声明十一次并添加我认为的一致性和简单性。
现在,这对于一个不需要 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;
这样可行,但有没有更好的方法来达到我的目的?
答案 0 :(得分:6)
好吧,由于没有尝试过最明显的解决方案,我有点愚蠢,只是在required
ness与默认值不同的派生类中覆盖属性定义。我们走了:
#!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
父类,为代码添加安全性和一致性。我相应地更新了我的示例代码。
答案 1 :(得分:1)
您可以将has '+key' => (requires => 1)
放在原始文件中,然后使用requires=> 1
将其关闭,而不是使用has '+key' => (requires => 0)
。在原始请求中,有11个是必需的,只有一个不需要,因此这意味着只有一个定义需要覆盖,而另外11个可以保持不变。