Каков наилучший способ реализации констант в Java? [закрыто]

372

Я видел такие примеры:

public class MaxSeconds {
   public static final int MAX_SECONDS = 25;
}

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

тип машины
источник

Ответы:

403

Это вполне приемлемо, возможно, даже стандарт.

(public/private) static final TYPE NAME = VALUE;

где TYPEтип, NAMEимя во всех заглавных буквах с подчеркиванием для пробелов и VALUEпостоянное значение;

Я настоятельно рекомендую НЕ помещать ваши константы в их собственные классы или интерфейсы.

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

Например:

public static final Point ORIGIN = new Point(0,0);

public static void main(String[] args){

    ORIGIN.x = 3;

}

Это законно, и ORIGINтогда будет точка в (3, 0).

jjnguy
источник
19
Вы даже можете «импортировать статические MaxSeconds.MAX_SECONDS;» так что вам не придется произносить его по буквам MaxSeconds.MAX_SECONDS
Аарон Маэнпаа
23
Предыдущий комментарий об импорте static относится только к Java 5+. Некоторые считают, что сокращение не стоит возможной путаницы относительно того, откуда взялась константа, при чтении длинного кода MaxSeconds.MAX_SECONDS может быть легче следовать, чем подниматься и смотреть на импорт.
MetroidFan2002
5
Поскольку вы можете изменить объект, как показал jjnguy, лучше всего, если ваши константы являются неизменяемыми объектами или просто простыми примитивами / строками.
Marcospereira
14
Если вы читаете этот вопрос, пожалуйста, прочитайте следующие два ответа ниже, прежде чем воспринимать этот ответ слишком серьезно, несмотря на то, что он принят, это противоречиво, если не неправильно.
orbfish
3
@jjnguy Вы не ошибаетесь, но если я прочитаю только вопрос и первые пару строк вашего ответа, у меня сложится впечатление, что «класс констант» «вполне приемлем, вероятно, даже стандарт». Это понятие является неправильным.
Зак Лысобей
235

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

  • Если у вас есть доступ к Java 5+, используйте перечисления для определения ваших конкретных констант для области приложения. Все части области приложения должны ссылаться на перечисления, а не на постоянные значения, для этих констант. Вы можете объявить перечисление, подобное тому, как вы объявляете класс. Перечисления, пожалуй, самая (и, пожалуй, единственная) полезная функция Java 5+.
  • Если у вас есть константы, которые действительны только для определенного класса или одного из его подклассов, объявите их как защищенные или общедоступные и поместите их в верхний класс в иерархии. Таким образом, подклассы могут получать доступ к этим константным значениям (и если другие классы получают к ним доступ через общедоступные, константы не только допустимы для определенного класса ... это означает, что внешние классы, использующие эту константу, могут быть слишком тесно связаны с класс, содержащий константу)
  • Если у вас есть интерфейс с определенным поведением, но возвращаемые значения или значения аргументов должны быть конкретными, вполне допустимо определить константы на этом интерфейсе, чтобы другие разработчики имели доступ к ним. Однако избегайте создания интерфейса только для хранения констант: он может стать таким же плохим, как класс, созданный просто для хранения констант.
MetroidFan2002
источник
12
полностью согласен ... это может быть задокументировано как классический шаблон для больших проектов.
Das
30
Не по теме, но ... Дженерики, конечно, не идеальны, но я думаю, что вы могли бы сделать довольно хороший пример того, что они являются полезной функцией Java 5 :)
Martin McNulty
3
@ ŁukaszL. Сам вопрос действительно основан на мнении (когда возникает «лучшее», это обычно вопрос мнения), поэтому ответ является верным ответом на этот вопрос. Я дал ответ относительно того, что (да, я полагаю , что да, так что да, это мнение, потому что опять «лучшие» изменяются со временем и, как правило, основано на мнении), лучший способ реализовать константы в Java.
MetroidFan2002
1
Ни один из приведенных выше вариантов не дает вам истинную глобальную переменную. Что если у меня есть что-то, что используется везде, но не является перечислением? Я делаю перечисление только одной вещи?
markthegrea
1
Если вам нужна глобальная константа, охватывающая все модули, возможно, что-то не так с вашей стратегией проектирования. Если вам действительно нужна глобальная константа, создайте для нее открытый финальный класс в пакете верхнего уровня и вставьте его туда. Затем удалите его, как только вы поймете, что не всем вашим классам действительно нужна эта константа, и переместите его в пакет, который ссылается на него больше всего. Вы можете совместно использовать константу в разных пакетах, но это запах кода, когда требуется глобальная константа, которая не является перечисляемым типом, поскольку перечисляемые типы могут иметь поведение, но строка - это строка, int - это int, и т. Д.
MetroidFan2002
120

Это плохая практика , чтобы использовать интерфейсы только , чтобы держать константы (названный постоянной шаблон интерфейса Джош Блох). Вот что советует Джош:

Если константы сильно привязаны к существующему классу или интерфейсу, вы должны добавить их в класс или интерфейс. Например, все классы числовых примитивов в штучной упаковке, такие как Integer и Double, экспортируют константы MIN_VALUE и MAX_VALUE. Если константы лучше всего рассматривать как члены перечислимого типа, вы должны экспортировать их с типом enum . В противном случае вы должны экспортировать константы с неинстансируемым служебным классом.

Пример:

// Constant utility class
package com.effectivejava.science;
public class PhysicalConstants {
    private PhysicalConstants() { }  // Prevents instantiation

    public static final double AVOGADROS_NUMBER   = 6.02214199e23;
    public static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
    public static final double ELECTRON_MASS      = 9.10938188e-31;
}

О соглашении об именах:

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

Марсио Агияр
источник
23
Если вы собираетесь называть что-то плохим, возможно, вам следует объяснить, почему вы так думаете?
GlennS 20.12.12
14
Это старый пост, но лучше использовать abstractнотацию для класса вместо частного конструктора.
Xtreme Biker
5
Мэтт, хотя рекомендации байкеров не являются ложными, я бы выступал за выпускные занятия, а не за абстрактные занятия. Байкер утверждал, что вы хотите убедиться, что ваш класс констант не подлежит изменению. Таким образом, пометив его как окончательный, вы не позволяете ему быть подклассами или созданными. Это также помогает инкапсулировать его статическую функциональность и не позволяет другим разработчикам разделять его на подклассы и заставлять делать то, для чего он не предназначен.
liltitus27
7
@XtremeBiker Маркировка класса abstractвместо частного конструктора не полностью предотвращает создание экземпляров, потому что можно создать его подкласс и создать экземпляр класса (не то, чтобы это было хорошей идеей, но это возможно). @ToolmakerSteve Вы не можете создать подкласс класса с приватным конструктором (по крайней мере, без большого неудачного взлома), потому что конструктор подкласса должен вызвать (теперь приватный) конструктор своего суперкласса. Таким образом, отмечать это finalне нужно (но, возможно, более явно).
импортировать это
3
Еще хуже использовать класс только для того, чтобы держать константы. Если вы никогда не хотите создавать объект этого класса, зачем вам использовать обычный класс ?
MaxZoom
36

В Effective Java (2-е издание) для констант рекомендуется использовать перечисления вместо статических целочисленных значений.

Хорошая рецензия на перечисления в Java здесь: http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html

Обратите внимание, что в конце этой статьи поставлен вопрос:

Итак, когда вы должны использовать перечисления?

С ответом:

Каждый раз, когда вам нужен фиксированный набор констант

shelfoo
источник
21

Просто избегайте использования интерфейса:

public interface MyConstants {
    String CONSTANT_ONE = "foo";
}

public class NeddsConstant implements MyConstants {

}

Это заманчиво, но нарушает инкапсуляцию и стирает различия между определениями классов.


источник
1
Действительно, статический импорт гораздо предпочтительнее.
Аарон Маенпаа
1
Эта практика является странным использованием интерфейсов, которые предназначены для определения служб, предоставляемых классом.
Рафа Ромеро
1
Я не согласен с тем, чтобы избежать использования интерфейса для констант, но я думаю, что ваш пример вводит в заблуждение. Вам не нужно реализовывать интерфейс, чтобы получить доступ к константе, потому что она неявно статическая, открытая и конечная. Итак, это проще, чем вы описали здесь.
Джангофан
Это правда ... это нарушает инкапсуляцию, я предпочитаю использовать последний класс Constant, который выглядит более ориентированно и предпочтительнее, чем интерфейс ИЛИ enum . Примечание: Enum можно избежать, если Android не нужен.
CoDe
19

Я использую следующий подход:

public final class Constants {
  public final class File {
    public static final int MIN_ROWS = 1;
    public static final int MAX_ROWS = 1000;

    private File() {}
  }

  public final class DB {
    public static final String name = "oups";

    public final class Connection {
      public static final String URL = "jdbc:tra-ta-ta";
      public static final String USER = "testUser";
      public static final String PASSWORD = "testPassword";

      private Connection() {}
    }

    private DB() {}
  }

  private Constants() {}
}

Чем, например, я пользуюсь, Constants.DB.Connection.URLчтобы получить константу. Это выглядит более "объектно-ориентированным", как для меня.

albus.ua
источник
4
Интересно, но громоздко. Почему бы вместо этого не создать константы в классе, наиболее тесно связанные с ними, как рекомендовано другими? Например, есть ли в вашем коде БД в другом месте базовый класс для ваших соединений? Например, "ConnectionBase". Тогда вы можете поместить константы там. Любой код, который работает с соединениями, скорее всего, уже имеет импорт, который может просто сказать «ConnectionBase.URL», а не «Constants.DB.Connection.URL».
ToolmakerSteve
3
@ToolmakerSteve Но как насчет общих констант, которые могут использовать несколько классов? например, стили, URL веб-сервисов и т. д.?
Даниэль Гомес Рико
Объединение всех констант в один класс имеет одно преимущество - обслуживание. Вы всегда точно знаете, где найти константы. Я не говорю, что это делает эту технику лучше, я просто предоставляю одно преимущество. И то, что сделал @ albus.ua, классифицировало его константы, что является хорошей идеей, особенно если класс констант содержит много много константных значений. Этот метод поможет сохранить класс управляемым и поможет лучше описать назначение константы.
Nelda.techspiress
17

Создание статических конечных констант в отдельном классе может привести к неприятностям. Компилятор Java фактически оптимизирует это и поместит фактическое значение константы в любой класс, который ссылается на нее.

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

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

Кевин Дэй
источник
+1 за эту отличную оговорку. (Если вы не можете гарантировать, что это постоянная константа, вместо этого рассмотрите метод получения, как упоминает big_peanut_horse.) Кстати, то же самое относится и к const в C #: msdn.microsoft.com/en-us/library/e6w8fe1b.aspx
Джон Кумбс
13

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

Вместо этого константы должны входить в класс, который «владеет» ими. У вас есть константа под названием TIMEOUT? Вероятно, он должен перейти в ваш класс Communications () или Connection (). MAX_BAD_LOGINS_PER_HOUR? Заходит в пользователя (). И так далее.

Другим возможным использованием являются файлы .properties Java, когда «константы» могут быть определены во время выполнения, но их нелегко изменить пользователем. Вы можете упаковать их в ваши .jars и ссылаться на них с помощью класса resourceLoader.

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

Это правильный путь.

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

Джейсон Коэн
источник
5

Как насчет перечисления?

Себастьян Д.
источник
5

Я предпочитаю использовать геттеры, а не константы. Эти геттеры могут возвращать значения констант, например public int getMaxConnections() {return 10;}, но все, что нуждается в константе, будет проходить через геттер.

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

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

big_peanut_horse
источник
5
Хорошая перекомпиляция ссылочных классов вряд ли является обузой в 21 веке. И вы никогда не должны использовать модель accessor / mutator (getter / setter) для чего-то другого, кроме доступа и изменения переменных-членов. Концептуально константы должны быть непосредственными по своей природе, в то время как геттеры / сеттеры (оба) предназначены для управления состоянием . Кроме того, вы только просите путаницы: люди не ожидают, что получатель даст простую константу.
5

Я согласен, что использование интерфейса - это не тот путь. Избегание этого шаблона даже имеет свой собственный элемент (# 18) в Эффективной Java Блоха .

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

public|private static final TYPE NAME = VALUE;Модель является хорошим способом объявить константу. Лично я думаю, что лучше избегать создания отдельного класса для размещения всех ваших констант, но я никогда не видел причины не делать этого, кроме личных предпочтений и стиля.

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

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

Роб Дикерсон
источник
Некоторые константы могут использоваться для вызова API. Например, см. Интерфейс org.springframework.transaction.TransactionDefinition. У него есть список констант, таких как int PROPAGATION_REQUIRED = 0;
Борхаб
Я знаю, что это старо, но ссылка на Эффективную Java Блоха не работает. Не могли бы вы предоставить другую или другую ссылку, подтверждающую, что «использование интерфейса - это не тот путь», пожалуйста?
Nelda.techspiress
4

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

public class Constants {

    private Constants() {
        throw new AssertionError();
    }

    public interface ConstantType {}

    public enum StringConstant implements ConstantType {
        DB_HOST("localhost");
        // other String constants come here

        private String value;
        private StringConstant(String value) {
            this.value = value;
        }
        public String value() {
            return value;
        }
    }

    public enum IntConstant implements ConstantType {
        DB_PORT(3128), 
        MAX_PAGE_SIZE(100);
        // other int constants come here

        private int value;
        private IntConstant(int value) {
            this.value = value;
        }
        public int value() {
            return value;
        }
    }

    public enum SimpleConstant implements ConstantType {
        STATE_INIT,
        STATE_START,
        STATE_END;
    }

}

Итак, я могу отнести их к как:

Constants.StringConstant.DB_HOST
Лоран Бендиг
источник
4
Почему? Как это улучшение? Каждая ссылка теперь громоздка (Constants.StringConstant.wh независимо). ИМХО, вы идете по ухабистой дороге здесь.
ToolmakerSteve
3

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

Брэдли Харрис
источник
1
Или вводится в этот класс через конструктор.
WW.
2

Есть определенное количество мнений, чтобы ответить на это. Начнем с того, что константы в Java обычно объявляются как public, static и final. Ниже приведены причины:

public, so that they are accessible from everywhere
static, so that they can be accessed without any instance. Since they are constants it
  makes little sense to duplicate them for every object.
final, since they should not be allowed to change

Я бы никогда не использовал интерфейс для объекта доступа / объекта CONSTANTS просто потому, что обычно ожидается, что интерфейсы будут реализованы. Разве это не выглядит смешно:

String myConstant = IMyInterface.CONSTANTX;

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

1.  Use a regular enum with a default/private constructor. Most people would define 
     constants this way, IMHO.
  - drawback: cannot effectively Javadoc each constant member
  - advantage: var members are implicitly public, static, and final
  - advantage: type-safe
  - provides "a limited constructor" in a special way that only takes args which match
     predefined 'public static final' keys, thus limiting what you can pass to the
     constructor

2.  Use a altered enum WITHOUT a constructor, having all variables defined with 
     prefixed 'public static final' .
  - looks funny just having a floating semi-colon in the code
  - advantage: you can JavaDoc each variable with an explanation
  - drawback: you still have to put explicit 'public static final' before each variable
  - drawback: not type-safe
  - no 'limited constructor'

3.  Use a Class with a private constructor:
  - advantage: you can JavaDoc each variable with an explanation
  - drawback: you have to put explicit 'public static final' before each variable
  - you have the option of having a constructor to create an instance
     of the class if you want to provide additional functions related
     to your constants 
     (or just keep the constructor private)
  - drawback: not type-safe

4. Using interface:
  - advantage: you can JavaDoc each variable with an explanation
  - advantage: var members are implicitly 'public static final'
  - you are able to define default interface methods if you want to provide additional
     functions related to your constants (only if you implement the interface)
  - drawback: not type-safe
djangofan
источник
2

Каков наилучший способ реализации констант в Java?

Один подход, которого мы должны избегать : использование интерфейсов для определения констант.

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

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


Чтобы упростить, у нас есть в целом 4 действительных подхода .

С static final String/Integerполем:

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

С Java 5 enum:

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

TLDR: Какой способ лучше всего и где найти константы?

В большинстве случаев путь enum, вероятно, более тонкий, чем static final String/Integerпуть, и лично я считаю, что этот static final String/Integerпуть следует использовать только в том случае, если у нас есть веские причины не использовать enum.
Что касается того, где мы должны объявлять постоянные значения, идея состоит в том, чтобы искать, существует ли единственный существующий класс, который обладает определенной и сильной функциональной связностью с постоянными значениями. Если мы найдем такой класс, мы должны использовать его в качестве держателя констант . В противном случае константа не должна быть связана ни с одним конкретным классом.


static final String/ static final Integerпротивenum

Использование Enums действительно способ, который настоятельно рекомендуется.
Перечисления имеют большое преимущество перед Stringили Integerпостоянное поле.
Они устанавливают более жесткие ограничения компиляции. Если вы определите метод, который принимает перечисление в качестве параметра, вы можете передать только значение перечисления, определенное в классе перечисления (или ноль).
С помощью String и Integer вы можете заменить их любыми значениями совместимого типа, и компиляция будет в порядке, даже если значение не является определенной константой в static final String/static final Integer полях .

Например, ниже двух констант, определенных в классе как static final Stringполя:

public class MyClass{

   public static final String ONE_CONSTANT = "value";
   public static final String ANOTHER_CONSTANT = "other value";
   . . .
}

Вот метод, который ожидает иметь одну из этих констант в качестве параметра:

public void process(String constantExpected){
    ...    
}

Вы можете вызвать это следующим образом:

process(MyClass.ONE_CONSTANT);

или

process(MyClass.ANOTHER_CONSTANT);

Но никакое ограничение компиляции не мешает вам вызывать его следующим образом:

process("a not defined constant value");

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

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

Например, здесь два значения, определенные в классе enum (поэтому постоянные из коробки):

public enum MyEnum {

    ONE_CONSTANT("value"), ANOTHER_CONSTANT(" another value");

    private String value;

    MyEnum(String value) {
       this.value = value;
    }
         ...
}

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

public void process(MyEnum myEnum){
    ...    
}

Вы можете вызвать это следующим образом:

process(MyEnum.ONE_CONSTANT);

или

process(MyEnum.ANOTHER_CONSTANT);

Но компиляция никогда не позволит вам вызвать его таким образом:

process("a not defined constant value");

Где мы должны объявить константы?

Если ваше приложение содержит один существующий класс, который обладает определенной и сильной функциональной связью с постоянными значениями, то 1) и 2) кажутся более интуитивными.
Как правило, это облегчает использование констант, если они объявлены в главном классе, который ими манипулирует, или у которого есть имя, и очень естественно догадываться, что мы найдем его внутри.

Например, в библиотеке JDK экспоненциальные значения и значения констант pi объявляются в классе, который объявляет не только константные объявления ( java.lang.Math).

   public final class Math {
          ...
       public static final double E = 2.7182818284590452354;
       public static final double PI = 3.14159265358979323846;
         ...
   }

Клиенты, использующие математические функции, часто полагаются на Mathкласс. Таким образом, они могут достаточно легко найти константы, а также могут вспомнить, где Eи как PIони определены очень естественным образом.

Если ваше приложение не содержит существующего класса, который имеет очень специфическую и сильную функциональную сплоченность с постоянными значениями, то варианты 1 и 2 будут казаться более интуитивными.
Как правило, это не облегчает использование констант, если они объявлены в одном классе, который ими манипулирует, в то время как у нас есть также 3 или 4 других класса, которые манипулируют ими так же, как и ни один из этих классов не кажется более естественным, чем другие. постоянные значения хоста.
Здесь определение пользовательского класса для хранения только постоянных значений имеет смысл.
Например, в библиотеке JDK java.util.concurrent.TimeUnitперечисление не объявлено в определенном классе, поскольку на самом деле не существует одного и только одного конкретного класса JDK, который представляется наиболее интуитивно понятным для его хранения:

public enum TimeUnit {
    NANOSECONDS {
      .....
    },
    MICROSECONDS {
      .....
    },
    MILLISECONDS {
      .....
    },
    SECONDS {
      .....
    },
      .....
}      

Многие классы объявляются в java.util.concurrentиспользовании их: BlockingQueue, ArrayBlockingQueue<E>, CompletableFuture, ExecutorService, ... и на самом деле не один из них не представляется более целесообразным провести перечисление.

davidxxx
источник
1

Константа любого типа может быть объявлена ​​путем создания неизменного свойства внутри класса (то есть переменной-члена с finalмодификатором). Как правило, staticи publicмодификаторы также предоставляются.

public class OfficePrinter {
    public static final String STATE = "Ready";  
}

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

public class OfficePrinter {
    public enum PrinterState { Ready, PCLoadLetter, OutOfToner, Offline };
    public static final PrinterState STATE = PrinterState.Ready;
}
Райан Делукки
источник
1

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

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


источник
1

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

Тим Хоулэнд
источник
1

В чем разница

1.

public interface MyGlobalConstants {
    public static final int TIMEOUT_IN_SECS = 25;
}

2.

public class MyGlobalConstants {
    private MyGlobalConstants () {} // Prevents instantiation
    public static final int TIMEOUT_IN_SECS = 25;
}

и использовать MyGlobalConstants.TIMEOUT_IN_SECSвезде, где нам нужна эта константа. Я думаю, что оба одинаковы.

chandrayya
источник
1
Похоже, что это, по сути, комментарий в ответ на ответ, который дал bincob. Я думаю, что они ведут себя очень похожим образом, но точка зрения Бинкоба заключалась в том, что они никоим образом не определяют интерфейс. И было предложено добавить константы в реальные классы, а не создавать скелетный класс MyGlobalConstants. (Хотя это иногда имеет смысл; используйте «статический класс», используя статические константы и закрытый конструктор для предотвращения создания экземпляров; см. Java.lang.math.) Рассмотрите возможность использования enum.
Джон Кумбс
Также добавление «final» в объявление класса предотвратит создание подклассов. (В C # вы можете сделать «static», что означает «финальный реферат», поэтому нет необходимости в явном частном конструкторе.)
Джон Кумбс
Да, @JonCoombs, но «final» не мешает его прямому созданию. А Java запрещает как окончательное, так и абстрактное отображение вместе для классов, и, следовательно, бесконечно появляющийся закрытый конструктор для предотвращения как создания экземпляров, так и создания подклассов. Я понятия не имею, почему «заключительный реферат» запрещен, кроме того, что на первый взгляд кажется противоречивым в том, как он гласит: «Вы не можете создавать подклассы, но этот класс предназначен для использования в подклассах».
0

Я бы не назвал класс тем же (кроме регистра), что и константой ... У меня был бы как минимум один класс «Настройки», или «Значения», или «Константы», где будут жить все константы. Если бы у меня их было много, я бы сгруппировал их в классы логических констант (UserSettings, AppSettings и т. Д.)

Джоэл Мартинес
источник
Я планировал заняться классом Constants, и это был лишь небольшой пример, который я нашел.
мк.
0

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

public interface MyGlobalConstants {
    public static final int TIMEOUT_IN_SECS = 25;
}

Но не воплощайте это в жизнь. Просто обратитесь к ним прямо в коде через полное имя класса.

Эндрю Хармел-Ло
источник
Смысл объявления их в интерфейсе (а не его реализации) заключается в том, что вы можете пропустить «публичный статический финал».
Том Хотин - tackline
9
Интерфейсы предназначены для определения поведенческого контракта, а не для удобства хранения констант.
Джон Топли
@JohnTopley Да, но это работает. ;)
trusktr
0

Для констант Enum - лучший выбор IMHO. Вот пример

открытый класс myClass {

public enum myEnum {
    Option1("String1", 2), 
    Option2("String2", 2) 
    ;
    String str;
            int i;

            myEnum(String str1, int i1) { this.str = str1 ; this.i1 = i }


}
mmansoor
источник
0

Один из способов сделать это - создать класс «Global» с постоянными значениями и выполнить статический импорт в классы, которым требуется доступ к константе.

Javamann
источник
0

static finalэто мое предпочтение, я бы использовал только, enumесли бы элемент был действительно перечислимым.

wulfgarpro
источник
0

я использую static final чтобы объявить константы и использовать обозначение имен ALL_CAPS. Я видел довольно много реальных случаев, когда все константы объединялись в интерфейс. Несколько постов справедливо назвали это плохой практикой, в первую очередь потому, что интерфейс не для этого. Интерфейс должен обеспечивать выполнение контракта и не должен быть местом для помещения не связанных между собой констант. Объединение его в класс, экземпляр которого не может быть создан (с помощью частного конструктора), тоже хорошо, если семантика констант не принадлежит конкретному классу ( эс). Я всегда помещаю константу в класс, с которым она больше всего связана, потому что это имеет смысл и также легко поддерживается.

Перечисления являются хорошим выбором для представления диапазона значений, но если вы храните автономные константы с акцентом на абсолютное значение (например, TIMEOUT = 100 мс), вы можете просто пойти на static finalподход.

bincob
источник
0

Я согласен с тем, что говорят большинство, лучше всего использовать перечисления при работе с коллекцией констант. Однако, если вы программируете на Android, есть лучшее решение: IntDef Annotation .

@Retention(SOURCE)
@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST,NAVIGATION_MODE_TABS})
public @interface NavigationMode {}
public static final int NAVIGATION_MODE_STANDARD = 0;
public static final int NAVIGATION_MODE_LIST = 1;
public static final int NAVIGATION_MODE_TABS = 2;
...
public abstract void setNavigationMode(@NavigationMode int mode);
@NavigationMode
public abstract int getNavigationMode();

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

Куинн Тернер
источник
Хотя я согласен с рекомендацией не использовать интерфейс только в Java и избегать использования enum в Android, эта замена в Android работает только при использовании небольшого количества полей. Это значительно экономит память, но может привести к раздуванию, поскольку вы будете использовать интерфейс для каждого поля в смешанном перечислении. Например, если у меня есть смешанное перечисление, которое определяет, что объект берет в своем конструкторе, я не могу ничего сохранить с этим подходом и возвращаюсь к не типичным безопасным константам, потому что в Android вы не хотите слишком много периодов классов / интерфейсов.
дроид
0

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

Я ничего не читал Джошуа Блох, так что либо

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

Как и в библейском фундаментализме, все библейские законы могут быть обобщены

  • Любите фундаментальную идентичность всем своим сердцем и всем своим разумом
  • Люби ближнего как самого себя

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

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

Кроме того, среди библейских фундаменталистских кругов обращается сильное и разумное следствие.

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

Точно так же, если вы не уважаете себя как программиста и просто принимаете высказывания и пророчества некоторых программистов-гуру, не ставя под сомнение основы, ваши цитаты и опора на Джошуа Блоха (и тому подобное) не имеют смысла. И поэтому вы на самом деле не будете уважать своих коллег-программистов.

Основные законы программирования

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

Константы шаблона интерфейса - плохая привычка ???

В какие законы фундаментально эффективного и ответственного программирования входит этот религиозный указ?

Просто прочитайте статью в Википедии о константах шаблона интерфейса ( https://en.wikipedia.org/wiki/Constant_interface ), и глупо оправдывать ее константы шаблона интерфейса.

  • Whatif-нет IDE? Кто на земле как программист не будет использовать IDE? Большинство из нас - программисты, которые предпочитают не доказывать наличие мачо-аскетического выживания, избегая использования IDE.

    • Кроме того - подождите секунду сторонники микро-функционального программирования как средство не нуждающихся в IDE. Подождите, пока вы не прочитаете мое объяснение о нормализации модели данных.
  • Загрязняет пространство имен переменными, не используемыми в текущей области? Это могут быть сторонники этого мнения

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

    • не видя, что «константы» должны рассматриваться как контракт. И интерфейсы используются для обеспечения или проецирования соответствия контракту.
  • Трудно, если не невозможно, преобразовать интерфейсы в реализованные классы в будущем. Хах .... хммм ... ???

    • Почему вы хотите заниматься такой моделью программирования, как постоянные средства к существованию? Итак, зачем посвящать себя такой АМБИВАЛЕНТНОЙ и вредной привычке программирования?

Каковы бы ни были оправдания, НЕТ ДЕЙСТВИТЕЛЬНОГО ПРИЧИНА, когда дело доходит до ФУНДАМЕНТАЛЬНО ЭФФЕКТИВНОЙ разработки программного обеспечения, чтобы делегитимизировать или вообще препятствовать использованию констант интерфейса.

Неважно, каковы были первоначальные намерения и психические состояния отцов-основателей, которые разработали Конституцию Соединенных Штатов. Мы могли бы обсудить первоначальные намерения отцов-основателей, но все, что меня волнует, - это письменные заявления Конституции США. И каждый гражданин США несет ответственность за использование письменного литературного фундаментализма, а не неписаных оснований Конституции США.

Точно так же меня не волнует, какие «оригинальные» намерения основатели платформы Java и языка программирования имели для интерфейса. Меня волнуют эффективные функции, предоставляемые спецификацией Java, и я намерен использовать эти функции в полной мере, чтобы помочь мне выполнить фундаментальные законы ответственного программирования. Мне все равно, если меня воспринимают как «нарушающее намерение интерфейсов». Меня не волнует, что Гослинг или кто-то другой Блох говорит о «правильном способе использования Java», если только то, что они говорят, не нарушает мою потребность в ЭФФЕКТИВНОМ выполнении основ.

Основой является нормализация модели данных

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

Сначала мы должны определить и нормализовать модель данных набора процессов. И когда у нас есть согласованная модель данных, ТОЛЬКО тогда мы можем использовать поток процессов его компонентов, чтобы определить функциональное поведение и блоки процессов в области или области приложений. И только тогда мы можем определить API каждого функционального процесса.

Даже аспекты нормализации данных, предложенные EF Codd, в настоящее время подвергаются серьезным и серьезным испытаниям. Например, его заявление о 1NF было подвергнуто критике как неоднозначное, смещенное и чрезмерно упрощенное, как и остальные его заявления, особенно в связи с появлением современных услуг передачи данных, технологий репо и передачи. IMO, заявления EF Codd должны быть полностью исключены, и должен быть разработан новый набор более математически правдоподобных утверждений.

Ярким недостатком Э. Ф. Кодда и причиной его несоответствия эффективному человеческому пониманию является его вера в то, что воспринимаемые человеком многомерные данные с изменчивыми измерениями могут быть эффективно восприняты посредством набора кусочных 2-мерных отображений.

Основы нормализации данных

Что Э. Ф. Кодд не смог выразить.

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

  1. Единство и идентичность экземпляров данных.
    • спроектировать детализацию каждого компонента данных, при этом их гранулярность находится на уровне, на котором каждый экземпляр компонента может быть уникально идентифицирован и получен.
    • отсутствие псевдонимов экземпляров. т.е. не существует средств, посредством которых идентификация производит более одного экземпляра компонента.
  2. Отсутствие примера перекрестных помех. Не существует необходимости использовать один или несколько других экземпляров компонента, чтобы способствовать идентификации экземпляра компонента.
  3. Единство и идентичность компонентов данных / измерений.
    • Наличие сглаживания компонентов. Должно существовать одно определение, посредством которого компонент / измерение может быть однозначно идентифицирован. Который является основным определением компонента;
    • где основное определение не приведет к раскрытию субразмерений или компонентов-элементов, которые не являются частью предполагаемого компонента;
  4. Уникальные средства компонентной разборки. Должно существовать одно и только одно такое определение сглаживания компонента для компонента.
  5. Существует один и только один интерфейс определения или контракт определения для идентификации родительского компонента в иерархической взаимосвязи компонентов.
  6. Отсутствие компонентных перекрестных помех. Не существует необходимости использовать элемент другого компонента, чтобы внести вклад в окончательную идентификацию компонента.
    • В таких отношениях родитель-потомок определение идентификатора родителя не должно зависеть от части набора компонентов-членов дочернего элемента. Компонент члена идентичности родителя должен быть полной дочерней личностью, не прибегая к ссылкам на всех или на всех детей ребенка.
  7. Превосходное бимодальное или мультимодальное появление модели данных.
    • Когда существует два определения кандидата для компонента, это является очевидным признаком того, что существуют две разные модели данных, смешанные в одну. Это означает, что существует несогласованность на уровне модели данных или на уровне поля.
    • Область приложений должна использовать одну и только одну модель данных, согласованно.
  8. Обнаружить и идентифицировать компонентную мутацию. Если вы не выполнили статистический компонентный анализ огромных данных, вы, вероятно, не увидите или не увидите необходимости лечения мутации компонентов.
    • Модель данных может иметь некоторые из своих компонентов мутировать циклически или постепенно.
    • Режим может быть вращением элемента или вращением перемещения.
    • Мутация ротации членов может быть явным обменом дочерних компонентов между компонентами. Или где совершенно новые компоненты должны быть определены.
    • Транспозиционная мутация проявляется в виде размерного члена, мутирующего в атрибут, и наоборот.
    • Каждый цикл мутации должен быть идентифицирован как отдельный мод данных.
  9. Версионизируйте каждую мутацию. Таким образом, вы можете извлечь предыдущую версию модели данных, когда, возможно, возникнет необходимость в лечении 8-летней мутации модели данных.

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

Мы все еще спрашиваем, можем ли мы использовать интерфейсные константы? В самом деле ?

На карту поставлены более важные вопросы нормализации данных, чем этот обыденный вопрос. Если вы не решите эти проблемы, путаница, которую, по вашему мнению, вызывают константы интерфейса, сравнительно ничто. Шиш.

После нормализации модели данных вы определяете компоненты как переменные, как свойства, как константы интерфейса контракта.

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

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

Возможно, вы хотите скомпилировать модель данных в выпуск vcs. Что вы можете вытащить четко идентифицируемую версию модели данных.

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

Так почему бы не опубликовать контракт модели данных? Я имею в виду, если вы можете согласованно и нормализовать это, то почему бы и нет? ...

public interface CustomerService {
  public interface Label{
    char AssignmentCharacter = ':';
    public interface Address{
      String Street = "Street";
      String Unit= "Unit/Suite";
      String Municipal = "City";
      String County = "County";
      String Provincial = "State";
      String PostalCode = "Zip"
    }

    public interface Person {
      public interface NameParts{
        String Given = "First/Given name"
        String Auxiliary = "Middle initial"
        String Family = "Last name"
      }
    }
  }
}

Теперь я могу ссылаться на контрактные ярлыки моих приложений таким образом, как

CustomerService.Label.Address.Street
CustomerService.Label.Person.NameParts.Family

Это смущает содержимое файла JAR? Как программист на Java, я не забочусь о структуре фляги.

Это представляет сложность для OSGI-мотивированного обмена времени выполнения? Osgi - чрезвычайно эффективное средство, позволяющее программистам продолжать вредные привычки. Есть лучшие альтернативы, чем osgi.

Или почему не это? Не существует утечки частных констант в опубликованный контракт. Все частные константы должны быть сгруппированы в закрытый интерфейс с именем «Константы», потому что я не хочу искать константы, и мне лень многократно набирать «private final String».

public class PurchaseRequest {
  private interface Constants{
    String INTERESTINGName = "Interesting Name";
    String OFFICIALLanguage = "Official Language"
    int MAXNames = 9;
  }
}

Возможно даже это:

public interface PurchaseOrderConstants {
  public interface Properties{
    default String InterestingName(){
       return something();
    }
    String OFFICIALLanguage = "Official Language"
    int MAXNames = 9;
  }
}

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

Это не "оригинальное намерение" интерфейсов? Как будто меня заботит «первоначальное намерение» отцов-основателей при разработке Конституции США, а не то, как Верховный суд будет толковать письменные письма Конституции США ???

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

Благословенный Компьютерщик
источник