Лучшие практики Java статические окончательные значения карты

У меня есть служебный класс, который содержит статическую конечную карту с некоторыми значениями. Мне нужен доступ к этой карте в другом классе. Должен ли я просто объявить карту общедоступной или мне следует написать геттер внутри служебного класса и, следовательно, сделать карту частной?

Оба способа работают, но каковы наилучшие методы?

public MyUtilityClass {
  public static final Map<String, Integer> MAX_LENGTHS = ImmutableMap.of(
      "title", 256,
      "text", 512);

}

public MyAnotherClass {

  public void someMethod() {
    //accessing the map directly
    MAX_LENGTHS.get("title")
  }

}

Или

public MyUtilityClass {
  private static final Map<String, Integer> MAX_LENGTHS = ImmutableMap.of(
      "title", 256,
      "text", 512);

  public static final getMaxLengthMap() {return MAX_LENGTHS;}
}

public MyAnotherClass {
  public void someMethod() {
    //accessing the map directly
    getMaxLengthMap().get("title")
  }
}

Ну, на самом деле ключи являются значениями перечисления. Что-то типа :

private static final Map<String, Integer> MAX_LENGTHS = ImmutableMap.of(
      MyEnumClass.TITLE, 256,
      MyEnumClass.TEXT, 512);

«Геттер» на MyUtilityClass, вероятно, должен возвращать значение ключа, а не пользователям класса, которые должны знать, что это за ключи или как они хранятся.

MadProgrammer 28.05.2019 11:38
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
5
1
832
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ответ принят как подходящий

Вы используете проект ImmutableMap from guava; таким образом, неизменяемый истинныйMap.

Сделать это public никому не повредит, так как никто не может изменить это Map каким-либо образом.

Геттер ничего не добавляет - я бы просто оставил его общедоступным.

Что может иметь смысл, так это иметь метод, который возвращает значение напрямую:

public MyUtilityClass {
  private static final Map<String, Integer> MAX_LENGTHS = ImmutableMap.of(
      "title", 256,
      "text", 512);

  public static final getMaxLength(String item) {return MAX_LENGTHS.get(item);}
}

public MyAnotherClass {
  public void someMethod() {
    //accessing the map directly
    getMaxLength("title");
  }
}

Это также позволяет вам легко изменить базовую реализацию позже. Например, вы можете вернуть значение по умолчанию для элементов, которых нет на карте и т. д.

Вы собираетесь засорять этот служебный класс методами Map... Завтра я захочу containsKey от MAX_LENGTHS, что мне делать?

Andrew Tobilko 28.05.2019 11:41

Это также правильный путь при определении пользовательских функций сопоставления в перечислениях, поскольку valueOf выдает неправильные имена.

roookeee 28.05.2019 11:42

@AndrewTobilko добавьте еще один метод. Это не мусорить. Рассмотрите возможность перечисления (если вам нужно перечислить значения) или используйте несколько вспомогательных классов.

roookeee 28.05.2019 11:43

@roookeee Я думаю, что это ... Вы собираетесь написать кучу методов Map только для резервного копирования частного поля один. Что, если бы у класса были другие поля/методы, не связанные с Map (что весьма вероятно для служебного класса)? (Раньше я использовал этот подход, теперь я не нахожу в нем ничего хорошего)

Andrew Tobilko 28.05.2019 11:52

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

Andrew Tobilko 28.05.2019 11:57

@AndrewTobilko Я не говорю, что это нужно делать именно так - я просто даю ОП еще один вариант. Основываясь на этом простом примере, я согласен с тем, что общедоступное поле совершенно нормально.

assylias 28.05.2019 12:06

@assylias да, это хороший момент. Мне нужно подумать, нужно ли мне возвращать значение по умолчанию или нет. Если мне это не нужно, я просто позволю ему быть общедоступным, поскольку он неизменяем.

josefk 28.05.2019 12:21

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

roookeee 28.05.2019 15:08

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

В вашем случае карта является окончательной и неизменной, поэтому это не применимо.

Но если вы хотите ограничить этот доступ только некоторым его содержимым, например title, то правильным выбором будет создание метода, который будет возвращать только String.

Установка карты как общедоступной или создание метода, который возвращает всю карту, не имеет значения.

Карта неизменна, поэтому ваши первые баллы не применяются.

assylias 28.05.2019 11:37

@Leviand изменять эту карту без каких-либо ограничений не для карты, которую использует OP.

Eugene 28.05.2019 11:37

Вы правы, я исправил свой ответ

Leviand 28.05.2019 11:39

Я думаю, что добавление геттера в класс-владелец было бы правильным.

public MyUtilityClass {
  private static final Map<String, Integer> MAX_LENGTHS = ImmutableMap.of(
      "title", 256,
      "text", 512);

  public static int getLength(final String key) {
     return MAX_LENGTHS.get(key);
  }
}

public MyAnotherClass {
  public void someMethod() {

    int x= MyUtilityClass.getLength("title")
  }
}

Это изолирует MyAnotherClass от необходимости знать какие-либо детали реализации геттера и значительно упрощает создание макетов для тестирования.

Я должен сказать, что вам, вероятно, лучше использовать Enum в первую очередь. Поскольку это сопоставление кажется всегда полностью статичным:

public enum MaxLength {
    TITLE(256),
    TEXT(512);

    public final int value;

    MaxLength(int value) {
        this.value= value;
    }
}

Больше нет необходимости в этом служебном классе, теперь вы можете просто получить значение напрямую:

int length = MaxLength.TITLE.value;

Другие вопросы по теме