Perl дизайн вопрос - PullRequest
       19

Perl дизайн вопрос

1 голос
/ 24 марта 2011

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

В основном ищем примеры сценариев, где ОО лучше, чем процедурный.

Спасибо!

Ответы [ 2 ]

5 голосов
/ 24 марта 2011

Прежде всего, чтобы уточнить, разница между процедурным и ОО не такая же, как разница между размещением всего вашего кода в одном файле и размещением его в отдельных модулях. Вы можете иметь отдельные модули, которые полны функций, которые вы вызываете процедурно.

В тех случаях, когда использование модулей, ОО или процедурных, выгодно, если код будет использоваться повторно или это просто большая кодовая база. Если у вас есть CMS с 10 различными сценариями CGI, которые выполняют несколько одинаковых действий, например, возможно, проверяют сеанс пользователя, тогда имеет смысл поместить этот код в отдельный модуль, а не переписывать его в каждом CGI. Если это функция из 20 строк, относящаяся к этому сценарию, оставьте ее в том же файле.

То, что вы делаете, зависит от того, будете ли вы заниматься ОО или процедурно. Большинство людей предпочитают ОО большую часть времени в эти дни. Я согласен с ними, так как считаю, что это поможет вам логически продумать ваш код и сгруппировать все вместе, что будет легко управлять и обновлять позже.

0 голосов
/ 24 марта 2011

Мне нравится помещать как можно больше своего кода в модули. Хорошая вещь о модулях в том, что вы можете использовать инструменты тестирования Perl (proof и Test :: More) для простого написания и управления модульными тестами. Так что, если почти весь ваш код находится в модулях, почти весь его можно тестировать.

Когда я пишу сценарий, мне нравится иметь тонкую оболочку, которая анализирует параметры конфигурации и параметры командной строки в моем сценарии (возможно, с использованием таких модулей, как Config :: Any или Getopt :: Long). Скрипт также содержит подпрограмму usage. Затем я добавляю подпрограмму main. main очень просто:

sub main {
    my $cfg = shift;

    my @collected_data;

    for my $file ( @{ $cfg->{files} ) {
        eval {
            my $fh = get_handle_from_file($file);

            my $xyz_data = parse_xyz_data( $fh );

            push @collected_data, extract_data( $xyz_data, $cfg->{filter} );

            1;
        } or do {
            my $e = $@;
            $e = "an unknown error occurred" unless defined $e;

            warn "Error parsing '$file': $e\n";
        };        
    }

    my %summary_data = summarize_data( @collected_data );

    write_summary( $cfg->{summary_target} );

    return;
}

Практически все вспомогательные подпрограммы будут жить в одном или нескольких модулях.

ООП - это хороший способ связать данные и поведение. Это может сделать код более читабельным и уменьшить беспорядок.

 $foo->eat_something( $sandwich )

легче понять, чем:

 eat_something( $sandwich, $likes_salty, $likes_sour, $likes_sweet, $likes_spicy );

Вся лишняя хрень собрана в удобные $foo атрибуты объекта и перемещается, не загромождая дополнительный вызов.

Конечно, вы можете сделать:

eat_something( $foo, $sandwich )

Где $ foo - это обычный хэш вкусовых предпочтений. По сути, это то, что делает Perl OO. Инвокант (имя объекта или класса) передается в качестве первого аргумента каждому методу. Вы теряете удобное пространство имен, наследование и вызовы динамических методов. Из трех затрат удобные пространства имен будут наиболее упущены. ИМО, наследование переоценено и должно использоваться только в редких случаях. Динамические вызовы методов могут быть полезны по тем же причинам, по которым удобны таблицы диспетчеризации.

В OO Perl нет ничего, что вы не могли бы сделать в процедурном Perl. Но OO делает некоторые вещи очень удобными.

Позвольте мне закончить, переписав мой мифический сценарий в ОО-стиле (я расскажу немного об ОО, только для иллюстрации):

sub main { мой $ cfg = shift;

    my $cd = Data::Collection->new();

    for my $file ( $cfg->files ) {
        eval {

            # skip the step of creating a handle first.  The parsing object
            # can take a file and get a handle or could be passed a handle.               

            my $xyz_parser = File::XYZ::Parse->new( file => $file );

            # The parser returns an XYZ::Data object

            my $xyz_data = $xyz_parser->parse;

            $cd->add_data( $xyz_data->extract_data( $cfg->filter );

            1;
        } or do {
            my $e = $@;
            $e = "an unknown error occurred" unless defined $e;

            warn "Error parsing '$file': $e\n";
        };        
    }

    # Skip the step of separate summarization, since the cd object can check if
    # the summary has been done, and if not generate and cache it as needed.

    $cd->write_summary( $cfg->summary_target );

    return;
}
...