Правильно ли получать и особенно устанавливать глобальные переменные модуля Perl напрямую? - PullRequest
7 голосов
/ 27 мая 2010

Мне было интересно, что лучше всего использовать в Perl для получения - или, что более важно, для установки - глобальной переменной некоторого модуля путем прямого доступа к $Module::varName в случае, если модуль не предоставил для него метод получения / установки.

Причина, по которой он пахнет плохо для меня, заключается в том, что он как бы обходит инкапсуляцию. Просто потому, что я могу сделать это в Perl, я не совсем уверен, что мне следует (при условии, что на самом деле есть альтернатива, такая как добавление модуля / установщика в модуль).

Ответы [ 4 ]

8 голосов
/ 27 мая 2010

Инкапсуляция не нарушается, если переменная является частью общедоступного API. (Если это не другое дело.)

Я думаю, что прямой доступ предпочтительнее, так как он позволяет вам использовать преимущества динамического определения объема:

local $Module::varName = 42;

Это делает конфликт с другим кодом, использующим Module менее вероятным.

2 голосов
/ 27 мая 2010

Глобальные переменные модуля были популярны в прошлом, но считались «плохой формой» как интерфейс в Modern Perl. Важно признать, что Perl сейчас 22-23 года, и стили и практики изменились. :) Обратите внимание, что бывают случаи, когда это все еще уместно, потому что есть некоторые очень хорошие функции, которые идут вместе с переменными пакета. Как обычно, это опыт и практика, чтобы понять, каким может быть хорошее решение.

Чтобы понять, как лучше всего использовать переменные пакета, вам действительно нужно понять, как работает local. Ознакомьтесь с справкой perldoc local . Local позволяет вам взять переменную пакета, например (например) $My::Variable в пакете My, и создать ее версию 1010 * с динамической областью действия. Обычно, если вы измените $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) всегда помогает.

Метод получения / установки с правильной инкапсуляцией объекта предотвращает многое из этого, но не всегда. Чтобы заставить его работать так, как работает локальная переменная, вам придется проделать много дополнительной работы. Самое замечательное в возможности локализовать переменную пакета - это то, что вы можете очень легко делать временные изменения, скажем, для отладочной переменной. Обычно вы должны сделать шаблон как:

{
    my $current_variable  My::get_variable();
    $My::set_variable($new_value);

    # Do code work

    $My::set_variable($current_variable);
}

Для местных это становится:

{
    local $My::Variable = $new_value;

    # do code work
}

(Между прочим, я бы хотел, чтобы вы могли делать это и с лексическими переменными, по той же причине ... но вы не можете.) Итак, для некоторых вещей переменные пакета могут иметь смысл. Это зависит от того, как вы хотите его использовать. Такие вещи, как

  • Отладка переменных
  • Глобальная конфигурация, которая не / не должна часто изменяться

Однако, если необходимо регулярно менять, например,

  • Регулярно используемые переменные (см. Ужасный интерфейс для File::Find)
  • Временная конфигурация
  • Переменные "объекта"

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

1 голос
/ 27 мая 2010

Если модуль не предоставляет средства доступа, создайте его, используйте его и отправьте исправление.

0 голосов
/ 27 мая 2010

Разве ввод-очистка / обработка ошибок не означает, что такое инкапсуляция?

Если в этом нет необходимости, то можно возразить против реализации геттеров и сеттеров, которые тогда выглядели бы глупо, как sub set_variable { $variable = shift; }.

Имейте в виду, использовать set_variable(42) проще, чем то, что предлагает Майкл

...