【问题标题】:Perl module class method vs ordinary subroutinePerl 模块类方法 vs 普通子程序
【发布时间】:2015-04-22 11:14:36
【问题描述】:

所以我想知道 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;

Package Bar 会保存我的类方法调用

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 中的语法例子。两者似乎天生就在做同样的事情,但似乎不止是表面上的。

【问题讨论】:

  • Always use strictuse warnings 在您编写的每个 Perl 程序的开头,无论如何琐碎的。在没有 strict 的情况下使用 my 几乎没有意义。
  • 相信我,我相信。我只是没有为这个示例编写它们,因为它不是问题核心的一部分。
  • 但是你包括了 shebang 行,到目前为止它不太相关!请始终根据最佳实践编写您的示例:您会受到更少的批评,更多阅读您的问题的人会相信这是一个好主意
  • 触摸。这是我的第一篇文章,所以我真的不知道会发生什么。编辑代码以反映这一点。
  • 很公平。请记住,Stack Overflow 不是一个论坛,而是一个旨在为大多数编程问题提供解决方案的资源——更像是由个人问题引发的维基百科。

标签: perl


【解决方案1】:

决定因素是您的Module 是否是面向对象的模块。

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

  • 1234563模块内部使用)。一个例子是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;

ma​​in.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

【讨论】:

    【解决方案2】:

    这更多是代码范式的问题。

    对您的代码采用非面向对象的方法绝对没有错。它有效,而且效果很好。

    但是,面向对象提供了许多值得考虑的好处 - 如果它们是您想要的东西,请走 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还有其他好处,我相信你可以谷歌)。

    【讨论】:

      【解决方案3】:

      普通子程序本身并没有错。他们做他们设计好的事情。

      另一方面,方法做所有相同的事情并且可以很好地与任何继承自你的类。

      所以问问自己:

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

      • 您的模块是对基本数据类型进行操作的实用程序库吗?

      在这个世界上两者都有足够的空间,但如果你发现自己,就像在 Bar 中所做的那样,在整个模块中忽略了 $class(或更常见的是 $self),那么也许你已经离开了远通过将它们设计为方法。更重要的是,当您的方法无法区分两个类之间的区别时,任何试图从您的边缘 OO“类”继承的人都会感到意外......

      【讨论】:

        猜你喜欢
        • 2012-09-27
        • 1970-01-01
        • 1970-01-01
        • 2018-10-09
        • 2012-10-08
        • 2021-06-12
        • 2021-02-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多