Perl模块类方法vs普通子例程

时间:2015-02-20 17:22:14

标签: perl

所以我想知道Perl类方法和标准模块中的普通子例程之间的使用是否有任何差异。你有没有时间使用其中一个?对于这个例子,我假设在任一模块中都没有对象方法。

这里快速的小主要课程:

#!/usr/local/bin/perl

use strict;
use warnings;

use Foo;
use Bar;

my $arg1 = "blah";
my ($str1, $str2);

$str1 = Foo::subroutine($arg1);
$str2 = Bar->subroutine($arg1);
exit(0);

Package Foo将保持我的普通子程序调用

use strict;
use warnings;

package Foo;

sub subroutine {
    my $arg = shift;
    my $string = "Ordinary subroutine arg is $arg\n";
    return $string;
}
1;

包栏会保存我的类方法调用

use strict;
use warnings;

package Bar;

sub subroutine {
    my $class = shift;
    my $arg = shift;
    my $string = "Class method arg is $arg\n";
    return $string;
}
1;

通常,如果我正在编写Perl代码,我只会使用类方法选项(就像使用Bar示例一样),但是在阅读了一位使用类似语法的前同事的代码后,我开始思考这个问题。 Foo的例子。两者似乎本身都做同样的事情,但似乎不仅仅是满足于眼睛。

3 个答案:

答案 0 :(得分:4)

决策者是你的Module是否是面向对象的模块。

  • 如果Module只是一个子程序集合的容器,那么我希望它使用Exporter并提供将其子程序的子集导入调用名称空间的机会。一个例子是List::Util

  • 另一方面,如果有一个构造函数Module::new,并且打算以OO方式使用它,那么你就不应该将简单的子程序与方法混合在一起(除了对于模块在内部使用的私有子例程。一个例子是LWP::UserAgent

所以我希望这些来源可以像其中一个或另一个一样写出来,而不是两者之间的混合。当然,在某些情况下应该忽略经验法则,但在这种情况下没有任何想法。

<强> Foo.pm

use strict;
use warnings;

package Foo;

use Exporter 'import';
our @EXPORT_OK = qw/ subroutine /;

sub subroutine {
    my ($arg)  = @_;
    "Ordinary subroutine arg is $arg\n";
}

1;

<强> Bar.pm

use strict;
use warnings;

package Bar;

sub new {
  my $class = shift;
  bless {}, $class;
}

sub subroutine {
    my $class = shift;
    my ($arg) = @_;
    "Class method arg is $arg\n";
}

1;

<强> main.pl

#!/usr/local/bin/perl

use strict;
use warnings;

use Foo 'subroutine';
use Bar;

my $arg1 = "blah";

print subroutine($arg1);
print Bar->subroutine($arg1);

<强>输出

Ordinary subroutine arg is blah
Class method arg is blah

答案 1 :(得分:2)

普通子程序没有任何内在错误。他们做了他们设计得很好的事情。

另一方面,方法完全可以与任何继承自你的类完美搭配。

所以问问自己:

  • 您是否期望/允许/鼓励人们编写从您的模块继承的类?
  • 您的模块是否定义了一个更复杂的数据结构,可以作为一个对象使用?

  • 您的模块是否是基于基本数据类型的实用程序库?

这两个世界都有足够的空间,但是如果你发现自己,就像你在Bar中所做的那样,在整个模块中忽略$class(或者更常见的是$self),那么也许你把它们设计成方法已经走得太远了。更重要的是,当你的方法无法区分这两个类别时,任何试图从你的边缘OO“级别”继承的人都会得到一个粗鲁的惊喜......

答案 2 :(得分:1)

这更像是一个代码范例的问题。

对于代码,非面向对象的方法绝对没有问题。它有效,而且效果很好。

然而,面向对象提供了一系列值得考虑的好处 - 如果它们是你想要的东西,那就去做OO路线吧。

具体而言 - 对象提供封装。这使我更容易编写模块而你只需使用它。比如说LWP::UserAgent为例:

 require LWP::UserAgent;

 my $ua = LWP::UserAgent->new;
 $ua->timeout(10);
 $ua->env_proxy;
 $ua->agent('Mozilla/5.0');

 my $response = $ua->get('http://search.cpan.org/');

 if ($response->is_success) {
     print $response->decoded_content;  # or whatever
 }
 else {
     die $response->status_line;
 }

现在,上面的所有都可以通过继承的子例程来完成。但是如果你想对多个页面进行多次提取,你要么必须:

  • 构建一个包含所需参数的子程序 - 包括以某种方式返回,“成功/失败/结果” - 可能在数组中?
  • 否则在您的外部模块中隐藏“状态”。
OO只是一种更简洁,更容易理解的方法。 (做OO还有其他好处,我相信你可以谷歌)。