Как определить класс констант в Java?

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

public static final String SOME_CONST = "SOME_VALUE";

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

  1. интерфейс
  2. Абстрактный Класс
  3. Заключительный Класс

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


пояснения к некоторым ответам:

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

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

10 ответов


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

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

в другой класс :

import static MyValues.*
//...

if(variable.equals(VALUE1)){
//...
}

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

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


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

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

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

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

3) интерфейс это будет работать, но не мое предпочтение, давая возможное упоминание злоупотребления в #2.

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


Как отмечает Джошуа блох в эффективной Java:

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

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

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

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

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


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

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


просто используйте final class.

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

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


не метки лучший выбор для таких вещей?


enums в порядке. 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.";
}

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

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


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

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

понятие перечисления - "перечисления-это наборы тесно связанных элементов".

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

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