Я задавался вопросом, что лучшая практика в Perl расценивает получение - или, что еще более важно, устанавливая - глобальная переменная некоторого модуля путем прямого доступа $Module::varName
в случае, если модуль не обеспечил метод считывания/метод установщика для него.
Причиной это плохо пахнет мне, является то, что это вид обходит инкапсуляцию. Просто, потому что я могу сделать это в Perl, я не совсем уверен, что я должен (принимающий там, на самом деле альтернатива, такая как добавление метода считывания/метода set к модулю).
Инкапсуляция не нарушается, если переменная является частью общедоступного API. (Если это не так, это другое дело.)
Я думаю, что прямой доступ предпочтительнее, так как он позволяет вам использовать преимущества динамической области видимости:
local $Module::varName = 42;
Это снижает вероятность конфликтов с другим кодом, использующим Модуль
.
Если модуль не предоставляет средства доступа, создайте его, используйте его и отправьте патч.
Разве санация ввода / обработка ошибок не является сутью инкапсуляции?
Если в этом нет необходимости, то можно возразить против реализации геттеров и сеттеров, которые затем выглядеть глупо вроде sub set_variable {$ variable = shift; }
.
Имейте в виду, проще использовать set_variable (42)
, чем предлагает Майкл !
Глобальные переменные модуля были в моде в прошлом, но считались «дурным тоном» в качестве интерфейса в современном Perl. Важно понимать, что Perl исполнилось 22-23 года, и стили и методы работы изменились. :) Обратите внимание, что бывают случаи, когда это все еще уместно, потому что есть несколько очень хороших функций, которые идут вместе с переменными пакета. Как обычно, увидеть, какое хорошее решение может быть хорошим решением, - вопрос опыта и практики.
Чтобы понять, как лучше всего использовать переменные пакета, вам действительно нужно понять, как работает local
. См. Справку по perldoc local
. Local позволяет вам взять переменную пакета, например $ My :: Variable
в пакете My
, и создать ее версию с динамической областью видимости . Обычно, если вы меняете $ My :: Variable
на месте, это повлияет на всю вашу программу и будет сохраняться. Для небольших программ это может не иметь большого значения. Для больших это может иметь катастрофические побочные эффекты. local
позволяет вам временно изменять эту переменную, которая ограничена вашей текущей областью действия.
Вот как это работает:
use 5.012;
use warnings;
package My;
our $Variable = 5;
package main;
say $My::Variable; # prints 5
$My::Variable = 7;
say $My::Variable; # prints 7
{ # create a new lexical scope
local $My::Variable = 10; # create a new dynamic scope for $My::Variable
# that will persist to the end of the lexical scope
say $My::Variable; # prints 10
}
say $My::Variable; # end of the lexical scope for the localized
# $My::Variable, so prints 7 again
Фактически, он позволяет безопасно использовать переменные пакета.К сожалению, не все знают о local, поэтому часто затирают глобальную переменную. Документирование правильного использования (например, local
) всегда помогает.
Геттер / сеттер с правильной инкапсуляцией объекта предотвращает многое из этого, но не всегда. Чтобы заставить его работать так, как это делает локальная переменная, вам придется проделать много дополнительной работы. Самое приятное в возможности локализовать переменную пакета - это то, что вы можете очень легко вносить временные изменения, например, для переменной отладки. Обычно вам нужно использовать шаблон вроде:
{
my $current_variable My::get_variable();
$My::set_variable($new_value);
# Do code work
$My::set_variable($current_variable);
}
С local это становится:
{
local $My::Variable = $new_value;
# do code work
}
(Кстати, я бы хотел, чтобы вы могли сделать то же самое и с лексическими переменными по той же причине ... но вы не можете.) Так что для некоторых вещей переменные пакета могут иметь смысл . Это зависит от того, как вы хотите его использовать. Такие вещи, как
Однако, если что-то, что делает, необходимо регулярно менять, например
File :: Find
) По сути, все, что нужно изменить более одного раза или в в редких случаях, или иначе он должен быть инкапсулирован в сгенерированный объект, тогда я бы избегал переменной пакета.