2015-02-20 3 views
5

Так что мне было интересно, есть ли разница в использовании между методом класса Perl и обычной подпрограммой из стандартного модуля. Есть ли время, когда вы будете использовать один над другим? В этом примере я предполагаю, что никакие объектные методы не присутствуют ни в одном из модулей.Метод класса модуля Perl vs обычная подпрограмма

Быстрый маленький главный класс здесь:

#!/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); 

Пакет Foo будет держать мой обычный вызов подпрограммы

use strict; 
use warnings; 

package Foo; 

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

пакет 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 e xample), но я начал размышлять над этим вопросом после прочтения кода от бывшего сотрудника, который использовал синтаксис, как в примере Foo. Оба, кажется, делают то же самое по своей сути, но, похоже, больше, чем кажется на первый взгляд.

+2

*** Всегда *** 'использование strict' и' использование warnings' в начале * каждый * программы Perl вы пишете, как бы ни тривиально. Очень мало смысла использовать 'my' без' strict' на месте. – Borodin

+0

Поверьте мне, я знаю. Я просто не писал их для этого примера, потому что это не было частью центрального ядра вопроса. – MeNoSeeGood

+0

Тем не менее вы включили линию shebang, которая менее актуальна далеко! Пожалуйста, всегда пишите свои примеры в соответствии с лучшей практикой: вы будете наказаны реже, и больше людей, которые читают ваши вопросы, будут считать, что это * хорошая идея *. – Borodin

ответ

2

В обычной подпрограмме нет ничего неправильного. Они делают то, что они разработали, чтобы делать очень хорошо.

Методы, с другой стороны, делают все те же вещи и прекрасно играют с любым классом, который наследуется от вашего.

Так спросите себя:

  • Вы ожидаете/разрешения/поощрения людей, чтобы писать классы, которые наследуют от модуля?
  • Является ли ваш модуль более сложной структурой данных, которая хорошо работает как объект?

или

  • Является ли ваш модуль библиотеки утилит, которые работают на основных типах данных?

Там много места в этом мире для обоих, но если вы нашли себя, как вы это делали в Bar, игнорируя $class (или чаще $self) по модулю, то, возможно, вы зашли слишком далеко, разработав их как методы. Что еще более важно, любой, кто пытается унаследовать ваш незначительный OO «класс», станет грубым сюрпризом, когда ваши методы не смогут отличить два класса ...

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, и я уверен, что вы могли бы Google).

3

Решите, является ли ваш Module объектно-ориентированным модулем или нет.

  • Если Module просто контейнер для сбора подпрограмм, то я ожидал бы использовать Exporter и дают возможность импортировать подмножество ее подпрограмм в вызывающем пространство имен. Пример может служить List::Util

  • С другой стороны, если есть конструктор Module::new, и намерение состоит в том, чтобы использовать его в ОО манере, то вы не должны смешивать простые подпрограммы с использованием методами (за исключением, возможно, для частных подпрограмм что модуль использует внутренне). Примером может служить 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); 

о utput

Ordinary subroutine arg is blah 
Class method arg is blah 
Смежные вопросы