防止 Moose 抽象的实例化 class
Prevent instantiation of a Moose abstract class
我正在将 Perl 与 Moose 一起使用,并且必须防止实例化抽象 class。
该项目处于相当先进的阶段 - 对于 Moose::Role
或 MooseX::*
来说太晚了。
我正在考虑根据 BUILDARGS
中的 class 名称检查包名称,
如果匹配,则调用 die
。
这种方法有什么问题吗?
package Foo::Abstract {
use Moose;
has 'test' => ( isa => 'Int', is => 'rw', default => '0' );
around BUILDARGS => sub {
die if $_[1] eq __PACKAGE__;
$orig = shift;
$class = shift;
$class->$orig( @_ );
};
no Moose;
}
package Foo::Concrete {
use Moose;
extends 'Foo::Abstract';
no Moose;
}
use Test::More;
use Test::Exception;
dies_ok { Foo::Abstract->new() } "cannot instantiate. OK";
my $c;
lives_ok { $c = Foo::Concrete->new() } "instantiated Foo::Concrete. OK";
ok( 0 == $c->test );
done_testing();
怎么来不及用角色?只需替换:
use Moose;
和
use Moose::Role;
并在 Foo::Concrete 中替换
extends 'Foo::Abstract';
和
with 'Foo::Abstract';
正如一些人在评论中指出的那样,您可能 应该 使用角色并在每个 "subclass" 中进行更改以进行组合。但是,您为懒惰提出了令人信服的论据(重构期间在一个地方进行了一次更改)。
我的建议是 "do both"。重构现有class你想抽象出来的角色:
mv lib/Foo/Abstract.pm lib/Foo/Role/Interface.pm;
perl -pie's/\bFoo::Abstract\b/Foo::Role::Interface/g' !$
然后在一个新的 Foo::Abstract
中简单地做:
package Foo::Abstract;
use Moose;
with qw(Foo::Role::Interface);
around BUILDARGS => sub {
$_[1] ne __PACKAGE__ ? shift->(@_) : die __PACKAGE__ . 'is ABSTRACT';
}
1;
这样您就可以随着时间的推移慢慢地用更合适的 with qw(Foo::Role::Interface)
替换 extends qw(Foo::Abstract)
,而不必一开始就付出所有代价。您甚至可以记录这是 Foo::Abstract
中的计划,以便其他一起来的开发人员帮助进行转换。
我正在将 Perl 与 Moose 一起使用,并且必须防止实例化抽象 class。
该项目处于相当先进的阶段 - 对于 Moose::Role
或 MooseX::*
来说太晚了。
我正在考虑根据 BUILDARGS
中的 class 名称检查包名称,
如果匹配,则调用 die
。
这种方法有什么问题吗?
package Foo::Abstract {
use Moose;
has 'test' => ( isa => 'Int', is => 'rw', default => '0' );
around BUILDARGS => sub {
die if $_[1] eq __PACKAGE__;
$orig = shift;
$class = shift;
$class->$orig( @_ );
};
no Moose;
}
package Foo::Concrete {
use Moose;
extends 'Foo::Abstract';
no Moose;
}
use Test::More;
use Test::Exception;
dies_ok { Foo::Abstract->new() } "cannot instantiate. OK";
my $c;
lives_ok { $c = Foo::Concrete->new() } "instantiated Foo::Concrete. OK";
ok( 0 == $c->test );
done_testing();
怎么来不及用角色?只需替换:
use Moose;
和
use Moose::Role;
并在 Foo::Concrete 中替换
extends 'Foo::Abstract';
和
with 'Foo::Abstract';
正如一些人在评论中指出的那样,您可能 应该 使用角色并在每个 "subclass" 中进行更改以进行组合。但是,您为懒惰提出了令人信服的论据(重构期间在一个地方进行了一次更改)。
我的建议是 "do both"。重构现有class你想抽象出来的角色:
mv lib/Foo/Abstract.pm lib/Foo/Role/Interface.pm;
perl -pie's/\bFoo::Abstract\b/Foo::Role::Interface/g' !$
然后在一个新的 Foo::Abstract
中简单地做:
package Foo::Abstract;
use Moose;
with qw(Foo::Role::Interface);
around BUILDARGS => sub {
$_[1] ne __PACKAGE__ ? shift->(@_) : die __PACKAGE__ . 'is ABSTRACT';
}
1;
这样您就可以随着时间的推移慢慢地用更合适的 with qw(Foo::Role::Interface)
替换 extends qw(Foo::Abstract)
,而不必一开始就付出所有代价。您甚至可以记录这是 Foo::Abstract
中的计划,以便其他一起来的开发人员帮助进行转换。