Мне нравится помещать как можно больше своего кода в модули. Хорошая вещь о модулях в том, что вы можете использовать инструменты тестирования 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;
}