Как вы определяете класс констант в Java? - PullRequest
65 голосов
/ 26 января 2009

Предположим, вам нужно определить класс, который все, что он делает, это содержит константы.

public static final String SOME_CONST = "SOME_VALUE";

Каков предпочтительный способ сделать это?

  1. Интерфейс
  2. Абстрактный класс
  3. Финальный класс

Какой я должен использовать и почему?


Разъяснения к некоторым ответам:

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

Интерфейс - Я не собираюсь устанавливать какой-либо класс как класс, реализующий интерфейс. Просто хочу использовать интерфейс для вызова констант вот так: ISomeInterface.SOME_CONST.

Ответы [ 10 ]

71 голосов
/ 26 января 2009

Используйте последний класс. для простоты вы можете использовать статический импорт для повторного использования ваших значений в другом классе

public final class MyValues {
  public static final String VALUE1 = "foo";
  public static final String VALUE2 = "bar";
}

в другом классе:

import static MyValues.*
//...

if(variable.equals(VALUE1)){
//...
}
36 голосов
/ 26 января 2009

Ваше уточнение гласит: «Я не собираюсь использовать перечисления, я ничего не перечисляю, просто собираю некоторые константы, которые никак не связаны друг с другом».

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

19 голосов
/ 07 апреля 2009

Мои предложения (в порядке убывания предпочтений):

1) Не делай этого . Создайте константы в фактическом классе, где они наиболее актуальны. Наличие класса / интерфейса «мешок констант» на самом деле не следует рекомендациям ОО.

Я и все остальные время от времени игнорируем # 1. Если вы собираетесь это сделать, то:

2) final класс с закрытым конструктором Это, по крайней мере, предотвратит злоупотребление вашей «сумкой констант», расширив / реализовав ее, чтобы получить легкий доступ к константам. (Я знаю, ты сказал, что не сделаешь этого, но это не значит, что кто-то придет после тебя)

3) interface Это будет работать, но я не предпочитаю упоминать о возможном злоупотреблении в # 2.

В общем, только потому, что это константы, не означает, что вы все равно не должны применять к ним нормальные принципы. Если никто, кроме класса, не заботится о константе - она ​​должна быть частной и в этом классе. Если только тесты заботятся о константе - это должен быть тестовый класс, а не рабочий код. Если константа определена в нескольких местах (а не случайно одна и та же) - рефакторинг для устранения дублирования. И так далее - относитесь к ним так же, как к методу.

12 голосов
/ 26 января 2009

Как отмечает Джошуа Блох в Effective Java:

  • Интерфейсы должны использоваться только для определения типов,
  • абстрактные классы не предотвращают инстанцируемость (они могут быть разделены на подклассы и даже предполагают, что они предназначены для подклассов).

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

class SomeConstants
{
    // Prevents instanciation of myself and my subclasses
    private SomeConstants() {}

    public final static String TOTO = "toto";
    public final static Integer TEN = 10;
    //...
}

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

6 голосов
/ 26 января 2009

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

Если вам не требуется совместимость с каким-либо устаревшим кодом, на самом деле больше нет причин использовать именованные строковые / целочисленные константы.

3 голосов
/ 26 января 2009

enum с в порядке. IIRC, один элемент в эффективной Java (2nd Ed) имеет enum константы, перечисляющие стандартные опции, реализующие [ключевое слово Java] interface для любого значения.

Я предпочитаю использовать [ключевое слово Java] interface вместо final class для констант. Вы безоговорочно получаете public static final. Некоторые люди будут утверждать, что interface позволяет плохим программистам реализовывать его, но плохие программисты будут писать код, который отстой, независимо от того, что вы делаете.

Что выглядит лучше?

public final class SomeStuff {
     private SomeStuff() {
         throw new Error();
     }
     public static final String SOME_CONST = "Some value or another, I don't know.";
}

Или:

public interface SomeStuff {
     String SOME_CONST = "Some value or another, I don't know.";
}
3 голосов
/ 26 января 2009

Разве не перечисления лучший выбор для такого рода вещей?

3 голосов
/ 26 января 2009

Просто используйте последний класс.

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

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

1 голос
/ 26 января 2009

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

... простите, не удержался; -)

0 голосов
/ 11 сентября 2015
  1. Одним из недостатков частного конструктора является то, что метод никогда не может быть проверен.

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

Концепция Enum такова: «Перечисления - это наборы тесно связанных элементов».

  1. Расширение / реализация константного интерфейса - плохая практика, трудно подумать о требовании расширить неизменяемую константу вместо прямой ссылки на нее.

  2. Если применять качественный инструмент, такой как SonarSource, есть правила, заставляющие разработчика отбрасывать постоянный интерфейс, это неловко, так как многие проекты пользуются постоянным интерфейсом и редко видят, как "расширенные" вещи происходят на постоянных интерфейсах 1018 *

...