Выбрать главу

Имя AccountVisitor сообщит много полезной информации программисту, знакомому с паттерном «Посетитель» (Visitor). И какой программист не знает, что такое «очередь заданий» (JobQueue)? Существует множество сугубо технических понятий, с которыми имеют дело программисты. Как правило, таким понятиям разумнее всего присваивать технические имена.

Используйте имена из пространства задачи

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

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

Добавьте содержательный контекст

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

Допустим, в программе используются переменные с именами firstName, lastName, street, houseNumber, city, state и zipcode. Вполне очевидно, что в совокупности они образуют адрес. Но что, если переменная state встретилась вам отдельно от других переменных внутри метода? Сразу ли вы поймете, что она является частью адреса?

Контекст можно добавить при помощи префиксов: addrFirstName, addrLastName, addrState и т.д. По крайней мере читатель кода поймет, что переменные являются частью более крупной структуры. Конечно, правильнее было бы создать класс с именем Address, чтобы даже компилятор знал, что переменные являются частью чего-то большего.

Возьмем метод из листинга 2.1. Нужен ли переменным более содержательный контекст? Имя функции определяет только часть контекста; алгоритм предоставляет все остальное. При чтении функции становится видно, что три переменные number, verb и pluralModifier являются компонентами сообщения guessМessage. К сожалению, контекст приходится вычислять. При первом взгляде на метод смысл переменных остается неясным.

Листинг 2.1. Переменные с неясным контекстом

private void printGuessStatistics(char candidate, int count) {

    String number;

    String verb;

    String pluralModifier;

    if (count == 0) {

      number = "no";

      verb = "are";

      pluralModifier = "s";

    } else if (count == 1) {

      number = "1";

      verb = "is";

      pluralModifier = "";

Листинг 2.1 (продолжение)

    } else {

      number = Integer.toString(count);

      verb = "are";

      pluralModifier = "s";

    }

    String guessMessage = String.format(

      "There %s %s %s%s", verb, number, candidate, pluralModifier

    );

    print(guessMessage);

  }

Функция длинновата, а переменные используются на всем ее протяжении. Чтобы разделить функцию на меньшие смысловые фрагменты, следует создать класс GuessStatisticsMessage и сделать три переменные полями этого класса. Тем самым мы предоставим очевидный контекст для трех переменных — теперь абсолютно очевидно, что эти переменные являются частью GuessStatisticsMessage. Уточнение контекста также позволяет заметно улучшить четкость алгоритма за счет его деления на меньшие функции (листинг 2.2).

Листинг 2.2. Переменные с контекстом

public class GuessStatisticsMessage {

  private String number;

  private String verb;

  private String pluralModifier;

  public String make(char candidate, int count) {

    createPluralDependentMessageParts(count);

    return String.format(

      "There %s %s %s%s",

       verb, number, candidate, pluralModifier );

  }

  private void createPluralDependentMessageParts(int count) {

    if (count == 0) {

      thereAreNoLetters();

    } else if (count == 1) {

      thereIsOneLetter();

    } else {

      thereAreManyLetters(count);

    }

  }

  private void thereAreManyLetters(int count) {

    number = Integer.toString(count);