perl - Moose 两次应用方法修饰符

标签 perl traits moose

基本架构

我用 perl 构建了一个信息检索工具,使用 Moose 作为框架。

我有一个用于插件的类层次结构,其中 Base 作为插件的公共(public)基类,特定插件的访问方法从中继承(方法是 HTTP、FTP、IMAP 等)。

从这些子类中,实际的工作类继承(每个数据源一个插件)。

我使用 Moose 角色将特定于源的行为组合到实际的工作类中(例如在 HTTP 源中启用对 SSL 客户端证书的支持)。

问题

其中一个方法特定类 (Base::A) 需要角色 R。相同的角色 R 也被角色 S 使用,然后由工作类 X 使用,继承自 Base::A.

我的问题是 R 中的方法修饰符对 X 应用了两次。有没有办法阻止 Moose 将方法修饰符应用于已经应用于其中一个父类的类?

例子

#!/usr/bin/env perl

use strict;
use warnings;
use utf8;

use v5.14;

{
    package R;

    use Moose::Role;

    before 'bar' => sub { say "R::before'bar'()" }
}

{
    package S;

    use Moose::Role;
    with 'R';

    before 'bar' => sub { say "S::before'bar'()" }
}

{
    package Base;

    use Moose;

    sub foo { say "Hello foo()"; }
}

{
    package Base::A;

    use Moose;
    extends 'Base';
    with 'R';

    sub bar { $_[0]->foo(); say "Hello bar()"; }
}

{
    package X;

    use Moose;
    extends 'Base::A';
    with 'S';
}


package main;

my $a = X->new();

$a->bar();

实际输出

S::before'bar'()
R::before'bar'()
R::before'bar'()
Hello bar()

预期输出

R::before'bar'() 行应该只出现一次。

最佳答案

首先,您的示例可以简单得多:

{
    package R;
    use Moose::Role;
    before 'bar' => sub { say "R::before'bar'()" }
}

{
    package Base;
    use Moose;
    with 'R';

    sub foo { say "Hello foo()"; }
    sub bar { $_[0]->foo(); say "Hello bar()"; }
}

{
    package X;
    use Moose;
    extends 'Base';
    with 'R';
}


package main;

X->new()->bar();

输出是:

R::before'bar'()
R::before'bar'()
Hello foo()
Hello bar()

为什么

我同意这有点出乎意料,但如果你仔细想想,这一切都是有道理的。角色不是基类,角色不是带有实现的接口(interface)(参见 Java),角色甚至不是 Python 意义上的“mixins”(在 Python 中我们实际上是从 mixins 继承的,但这只是语言限制)。角色只是您应用于您的类(class)的一堆功能(属性、方法、修饰符等)。这是一次性的 Action 。具有角色的类不会“记住”它,它只是在创建类时被应用。您不从角色继承,所以您不应该期望 Moose 实现一些 diamond合并同一角色的多个申请。

另一方面,如果您尝试执行 with qw(R S);然后 R令人惊讶的是(或者可能不是真的)只应用了一次。

做什么

现在进入实际问题。由于您希望“之前”相互覆盖,因此您可以放弃使用 before完全并将其重构为一个简单的方法(就像您在不支持此类修饰符的任何其他语言中所做的那样):

sub bar {
    my ($self) = @_;

    $self->_before_bar_hook();
    # ...
}

sub _before_bar_hook {}

结论

前后修饰符和角色都是非常高级的 Moose 功能,我对某些奇怪的副作用(如您所发现的)并不感到惊讶。尽管我相信我的解释大部分是正确的,但我不建议使用需要此类解释的内容。

我个人完全避免使用前/后修饰符,因为我更喜欢显式调用 Hook (如上所示)。

关于perl - Moose 两次应用方法修饰符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45999416/

相关文章:

php - php中多重继承的最佳方式是什么?

Function0 上的 Scala 堆栈修改

scala - Scala 中的线性化顺序

perl - 即使子类覆盖该属性,也会默认使用 Moose 属性

perl - Path::Class::File 或::Dir & Moose 初始化和强制

perl - 扩展 Moose 对象类的构造顺序是什么?

perl - 在子进程中重定向 STDOUT

linux - Perl 脚本将换行符添加到文本文件末尾

perl - 如何检查 Perl 中是否已创建对象?

perl - 在 Perl 中,为什么复制弱引用会创建正常的强引用?