什么是间接对象表示法,为什么它不好,以及如何避免它?

时间:2015-10-05 18:15:07

标签: perl oop coding-style perl5

标题几乎总结了它,但无论如何这里是长版本。

在发布一小段perl代码后,我被告知要避免使用间接对象表示法,因为它有几个副作用"。评论引用了这一特定的一行:

my $some_object = new Some::Module(FIELD => 'value');

因为这就是我一直以来的做法,为了与时俱进,我因此要求:

  • 它有什么不好的? (具体地)
  • 潜在的(可能是负面的)副作用是什么?
  • 如何重写该行?

我正打算问这位评论者,但对我而言,这是值得发表的。

4 个答案:

答案 0 :(得分:18)

主要问题是它含糊不清。确实

my $some_object = new Some::Module(FIELD => 'value');

意味着调用new包中的Some::Module方法,或者是否意味着调用当前包中的new函数,调用Module的结果具有给定参数的Some包中的函数?

即,它可以解析为:

# method call
my $some_object = Some::Module->new(FIELD => 'value');
# or function call
my $some_object = new(Some::Module(FIELD => 'value'));

另一种方法是使用显式方法调用符号Some::Module->new(...)

通常情况下,解析器会正确猜测,但最佳做法是避免歧义。

答案 1 :(得分:9)

  

它有什么坏处?

间接方法表示法的问题是可以避免的,但是告诉人们避免使用间接方法表示法要容易得多。

主要问题是很容易意外地调用错误的功能。请使用以下代码,例如:

package Widget;

sub new { ... }
sub foo { ... }
sub bar { ... }

sub method {
   ...;
   my $o = new SubWidget;
   ...;
}

1;

在该代码中,new SubWidget预计意味着

SubWidget->new()

相反,它实际上意味着

new("SubWidget")

那就是说,使用strict会捕获这个错误的大部分实例。如果要将use strict;添加到上面的代码段,则会产生以下错误:

Bareword "SubWidget" not allowed while "strict subs" in use at Widget.pm line 11.

也就是说,有些情况下使用strict不会捕获错误。它们主要涉及在方法调用的参数周围使用parens(例如new SubWidget($x))。

这意味着

  • 使用没有parens的间接对象表示法可能会导致奇怪的错误消息。
  • 使用带有parens的间接对象表示法可能会导致调用错误的代码。

前者是可以忍受的,而后者是可以避免的。但是,与其告诉人们避免使用间接方法表示法#34;围绕方法调用的参数使用parens,我们只是告诉人们"避免使用间接方法表示法"。它太脆弱了。

还有另一个问题。它不只是使用间接对象表示法是一个问题,它在Perl中支持它。该特征的存在导致多个问题。首先,

  • 它导致一些语法错误导致非常奇怪/误导性的错误消息,因为代码似乎是在它不是时使用ION。
  • 它阻止实现有用的功能,因为它们与有效的ION语法冲突。

从好的方面来说,使用no indirect;可以解决第一个问题。

  

如何重写该行?

编写方法调用的正确方法如下:

my $some_object = Some::Module->new(FIELD => 'value');

尽管如此,即使这种语法也不明确。它将首先检查名为Some::Module的函数是否存在。但是,很少有人能够保护自己免受此类问题的影响。如果您想保护自己,可以使用以下内容:

my $some_object = Some::Module::->new(FIELD => 'value');

答案 2 :(得分:6)

至于如何避免它:有一个CPAN模块禁止表示法,就像一个pragma模块:

no indirect;

http://metacpan.org/pod/indirect

答案 3 :(得分:4)

评论者只是想看Some::Module->new(FIELD => 'value');作为构造函数。

Perl可以使用indirect object syntax for other bare words that look like they might be methods,但现在perlobj文档建议不要使用它。

它的一般问题是以这种方式编写的代码是不明确的,并且运用Perl的解析器来测试命名空间,例如:检查编写method Namespace时是否存在Namespace :: method。