防止实例化Moose抽象类

时间:2017-11-03 20:13:08

标签: perl abstract-class moose

我正在使用Perl和Moose,并且必须阻止实例化抽象类。

该项目处于相当高级的阶段 - 对Moose::RoleMooseX::*来说太晚了。

我正在考虑根据BUILDARGS中的类名检查包名称, 如果匹配则调用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();

2 个答案:

答案 0 :(得分:1)

使用Roles为时已晚?只需替换:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="suffix1">addClass suffix1</a>
<a href="http://">don't add</a>
<a href="suffix2">addClass suffix2</a>
<a href="https://">don't add</a>

use Moose;

在Foo :: Concrete中,替换

use Moose::Role;

extends 'Foo::Abstract';

答案 1 :(得分:1)

正如有几个人在评论中指出的那样,你可能使用一个角色并在每个&#34;子类&#34;中进行更改。做作文。然而,你为懒惰做出了令人信服的论证(在重构过程中,一个地方发生了一次变化)。

我的建议是&#34;做两个&#34;。将您希望抽象出来的现有类重构为一个角色:

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;

通过这种方式,您可以使用更合适的extends qw(Foo::Abstract)慢慢替换with qw(Foo::Role::Interface),但不必预先支付该费用。您甚至可以在Foo::Abstract中记录这是该计划,以便其他开发人员帮助您进行转换。