Як ви визначаєте клас констант в Java?


89

Припустимо, вам потрібно визначити клас, у якому він лише має константи.

public static final String SOME_CONST = "SOME_VALUE";

Який найкращий спосіб зробити це?

  1. Інтерфейс
  2. Анотація класу
  3. Підсумковий клас

Який із них мені використовувати і чому?


Роз’яснення до деяких відповідей:

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

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


Тут є кілька подібних дискусій: stackoverflow.com/questions/320588/… . Я б використав фінальний клас із приватним конструктором, щоб його не можна було створити.
Ден Дайер,

2
Вибачте, але "Я не буду використовувати перелічення" перетворює це питання на "який найкращий спосіб зробити щось дурне?"
cletus

Я не кажу, що ви збираєтесь впровадити інтерфейс. Але немає сенсу використовувати для цього інтерфейс. Отже, переходьте до фінального класу
:)

У чому проблема Enum? Ви завжди можете використовувати його для збору "деяких констант, які ніяк не пов'язані між собою". Хм?
gedevan

5
Концептуально перерахування є поганим вибором, якщо константи не пов'язані між собою. Перелік представляє альтернативні значення того ж типу. Ці константи не є альтернативами, і вони можуть бути навіть не одного типу (деякі можуть бути рядками, деякі цілі числа тощо)
Ден Дайер,

Відповіді:


92

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

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

в іншому класі:

import static MyValues.*
//...

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

4
Де вигода від створення окремого класу тут? Хоча я зазвичай не вважаю API календаря гарним прикладом дизайну, це нормально з точки зору "константи, пов'язані з календарем, знаходяться в класі календаря".
Джон Скіт,

7
Перевага полягає в не дублюванні коду, якщо вам потрібно повторно використовувати константи в більш ніж одному класі. Думаю, ви легко можете переконатись у перевазі цього.
user54579

2
Чому ви дублюєте код? Просто зверніться до іншого класу. Я вважаю відносно рідким, щоб константа справді стояла поодинці.
Джон Скіт,

14
Для кращої читабельності я б також мав приватний конструктор за замовчуванням без тіла (та відповідного коментаря).
Ран Бірон

5
Досить стара відповідь, і цей коментар, мабуть, недоречний, але я б використав, VALUE1.equals(variable)оскільки він дозволяє уникнути NPE.
Aakash

38

У вашому роз'ясненні сказано: "Я не збираюся використовувати перелічення, я нічого не перелічую, просто збираю деякі константи, які ніяк не пов'язані між собою".

Якщо константи взагалі не пов’язані між собою, чому ви хочете збирати їх разом? Помістіть кожну константу в клас, з яким він найтісніше пов'язаний.


2
Джон - вони споріднені в тому сенсі, що всі вони належать до однієї і тієї ж функціональності. Однак вони не є переліком нічого ... Вони не мають властивості, що об'єкт є "однією з цих речей".
Юваль Адам

13
Добре. У такому випадку просто поставте їх до класу, який є найближчим до функціональних можливостей, з якими вони пов’язані.
Джон Скіт,

26

Мої пропозиції (у порядку зменшення переваг):

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

Я та всі інші час від часу ігноруємо №1. Якщо ви збираєтеся це зробити, тоді:

2) заключний клас із приватним конструктором Це, принаймні, запобіжить зловживанню вашим "мішком констант", розширивши / впровадивши його, щоб отримати легкий доступ до констант. (Я знаю, ви сказали, що не будете цього робити, але це не означає, що хтось прийде після вас)

3) інтерфейс Це спрацює, але не за моїми уподобаннями, згадавши про можливе зловживання в №2.

Загалом, те, що це константи, не означає, що ви все одно не повинні застосовувати до них нормальні принципи oo. Якщо ніхто, крім одного класу, не піклується про константу - вона повинна бути приватною і в цьому класі. Якщо лише тести піклуються про константу - вона повинна бути в тестовому класі, а не в виробничому коді. Якщо константа визначена в декількох місцях (не просто випадково однаково) - рефактор для усунення дублювання. І так далі - поводьтеся з ними так, як із способом.


2
Проблема 1 полягає в тому, що іноді ви вставляєте у свій код деякі залежності до іншого класу рівня, щоб отримати константу.
amdev

Усі поля в інтерфейсі неявно загальнодоступні, статичні та остаточні
Kodebetter

@Kodebetter Але інтерфейси можуть бути розширені / реалізовані, щоб додати більше полів.
Віт

12

Як зазначає Джошуа Блох в 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;
    //...
}

Потім, як уже було сказано, ви можете використовувати статичні імпорти, щоб використовувати свої константи.


7

Мені більше подобається не робити цього взагалі. Вік констант майже помер, коли Java 5 представила безпечні перелічення типів. І навіть до того Джош Блох опублікував (трохи більш багатослівний) її варіант, який працював на Java 1.4 (і раніше).

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


2
Гарна відповідь, приклад буде кращим.
amdev

3

Просто використовуйте заключний клас.

Якщо ви хочете мати можливість додавати інші значення, використовуйте абстрактний клас.

Використовувати інтерфейс не має особливого сенсу, інтерфейс повинен вказувати контракт. Ви просто хочете оголосити деякі константи.



3

enums добре. IIRC, один елемент в ефективній Java (2-е видання) має enumконстанти, що перераховують стандартні параметри, що реалізують [ключове слово Java] interfaceдля будь-якого значення.

Моя перевага - використовувати [ключове слово Java] interfaceнад a final classдля констант. Ви неявно отримуєте public static final. Деякі люди будуть стверджувати, що a 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.";
}

але погані програмісти збираються писати код, який відмовляє незалежно від того, що ви робите. Це лише так вірно. Якщо ви можете вжити заходів для пом'якшення поганого програмування або взагалі його усунути, тоді ви несете певну відповідальність за це; бути максимально явними. Поганий програміст не може продовжити фінальний клас.
liltitus27,

1
@ liltitus27 Певною мірою я згоден. Але чи дійсно ви хочете, щоб збіднений код просто зупинив один із способів поганих програмістів писати поганий код? Код, який вони виробляють, все ще буде безнадійним, але тепер ваш код стає менш читабельним.
Tom Hawtin - таклін

1

Або 4. Помістіть їх у клас, що містить логіку, яка найбільше використовує константи

... вибачте, не втримався ;-)


3
Це не дуже гарна ідея. Це створює залежності між класами, яких не повинно бути.
Юваль Адам

Чому ні? Я б сказав, що класи, які використовують однакові константи, все одно мають залежність ... І якимось чином повинен бути один клас, який найбільше залежить від цих констант.
Саймон Гріневольт

Якби лише один клас використовував константи, це могло б мати сенс.
Том Хоутін - таклін

-1
  1. Одним з недоліків приватного конструктора є існування методу, який ніколи не може бути перевірений.

  2. Перелік за природою поняття добре застосовувати в конкретному типі домену, застосовувати його до децентралізованих констант виглядає недостатньо добре

Концепція Enum - "Переліки - це набори тісно пов'язаних елементів".

  1. Розширення / реалізація постійного інтерфейсу є поганою практикою, важко думати про вимогу розширити незмінну константу замість того, щоб посилатися на неї безпосередньо.

  2. Якщо застосувати інструмент якості, такий як SonarSource, існують правила, які змушують розробника відмовлятися від постійного інтерфейсу, це незручно, оскільки багато проектів користуються постійним інтерфейсом і рідко бачать, як на постійних інтерфейсах відбувається щось «розширення»


1
"приватний конструктор - це існування методу, який ніколи не можна перевірити": не відповідає дійсності. Якщо ви (або ваш начальник) справді параноїчні щодо того, що звіти про покриття коду становлять 100%, ви все одно можете перевірити це, використовуючи відображення та забезпечуючи, щоб конструктор видавав виняток. Але, ІМХО, це лише формальність і насправді не потрібно перевіряти. Якщо вас (або команду) цікавить лише те, що насправді важливо, 100% покриття лінії не потрібно.
L. Holanda
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.