Який найкращий спосіб впровадити константи на Java? [зачинено]


372

Я бачив такі приклади:

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

і припускав, що я можу мати клас Константи, щоб обертати константи, оголошуючи їх статичними остаточними. Я практично не знаю Java і мені цікаво, чи це найкращий спосіб створення констант.


1
просто додати константи java: public / private
ms_27

Відповіді:


403

Це цілком прийнятно, мабуть, навіть стандарт.

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

де TYPEтип, NAMEце ім'я у всіх кришках з підкресленнями пробілів і VALUEє постійним значенням;

Я настійно не рекомендую розміщувати константи у власних класах чи інтерфейсах.

Як бічна примітка: Змінні, які оголошуються остаточними та є змінними, все ще можуть бути змінені; однак змінна ніколи не може вказувати на інший об’єкт.

Наприклад:

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

public static void main(String[] args){

    ORIGIN.x = 3;

}

Це законно, і ORIGINтоді було б питання (3, 0).


19
Ви навіть можете "імпортувати статичні MaxSeconds.MAX_SECONDS;" так що вам не доведеться писати це MaxSeconds.MAX_SECONDS
Aaron Maenpaa

23
Попередній коментар про статичний імпорт стосується лише Java 5+. Деякі вважають, що скорочення не вартує можливої ​​плутанини щодо того, звідки з'явилася константа, читаючи довгий код, MaxSeconds.MAX_SECONDS може бути легше прослідкувати, а потім піднятися і подивитися на імпорт.
MetroidFan2002

5
Оскільки ви можете змінити objetc, як показали jjnguy, найкраще, якщо ваші константи є незмінними об'єктами або просто простими примітивами / рядками.
marcospereira

14
Якщо ви читаєте це запитання, будь ласка, прочитайте наступні два відповіді нижче, перш ніж сприймати цю відповідь занадто серйозно, незважаючи на те, що її прийняли, це суперечливо, якщо не неправильно.
orbfish

3
@jjnguy Ви не помиляєтесь, але якби я прочитав лише запитання та перші пару рядків вашої відповіді, я мав би враження, що "клас констант" є "цілком прийнятним, напевно, навіть стандартним". Це поняття є неправильним.
Зах Лісобей

235

Я б дуже радив не мати єдиного класу констант. Тоді це може здатися гарною ідеєю, але коли розробники відмовляються документувати константи і клас зростає до 500 констант, які взагалі не пов'язані між собою (пов'язані з абсолютно різними аспектами програми), це як правило, файл константи абсолютно не читається. Замість цього:

  • Якщо у вас є доступ до Java 5+, використовуйте перерахунки, щоб визначити ваші конкретні константи для області додатків. У всіх частинах області застосування для цих констант повинні бути вказані перерахунки, а не постійні значення. Ви можете оголосити перерахунок, подібний до того, як ви оголошуєте клас. Енуми - це, мабуть, найбільш (і, мабуть, єдине) корисна особливість Java 5+.
  • Якщо у вас є константи, які відповідають дійсності лише певному класу або одному з його підкласів, оголосьте їх як захищені або загальнодоступні та розмістіть їх у вищому класі в ієрархії. Таким чином, підкласи можуть отримати доступ до цих постійних значень (а якщо інші класи отримують доступ до них через загальнодоступні, константи не є дійсними лише для певного класу ... це означає, що зовнішні класи, що використовують цю константу, можуть бути занадто щільно пов'язані з цим клас, що містить константу)
  • Якщо у вас інтерфейс із визначеною поведінкою, але повернені значення або значення аргументу повинні бути конкретними, цілком прийнятно визначати константи на цьому інтерфейсі, щоб інші виконавці мали доступ до них. Однак уникайте створення інтерфейсу просто для утримання констант: він може стати таким же поганим, як клас, створений просто для утримання констант.

12
повністю згоден ... це може бути зафіксовано як класичний антидіапазон для великих проектів.
Дас

30
Немає теми, але ... Generics, безумовно, не є ідеальними, але я думаю, ви могли б зробити гарний випадок для них корисною особливістю Java 5 :)
Мартін МакНтилті

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

14
Це стара публікація, але краще використовувати abstractпозначення для класу замість приватного конструктора.
Xtreme Biker

5
Метт, хоча рекомендація байкера не є хибною, я б виступав за випускні класи, а не абстрактні заняття. Байкерський пункт говорив про те, що ви хочете переконатися, що ваш клас констант не може бути змінений. Отже, позначаючи його як остаточне, ви не дозволяєте йому підкласифікуватись або помірковано. Це також допомагає інкапсулювати його статичну функціональність і не дозволяє іншим розробникам підкласифікувати його і змусити його робити те, чого він не розробляв.
liltitus27

7
@XtremeBiker Позначення класу abstractзамість приватного конструктора не повністю запобігає екземпляру, оскільки можна було б його підкласифікувати та інстанціювати підклас (не те, що це добре робити, але це можливо). @ToolmakerSteve Ви не можете підкласирувати клас із приватним конструктором (принаймні, без великого поганого злому), тому що конструктору підкласу необхідно викликати (тепер приватний) конструктор його суперкласу. Отже, маркування це finalзайве (але, можливо, більш чітке).
імпортувати цього

3
Ще гірше використовувати клас просто для утримання констант. Якщо ви ніколи не хочете створити об'єкт цього класу, чому ви в першу чергу використовуєте звичайний клас ?
MaxZoom

36

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

Тут є хороша кількість записів про перерахування на Java: http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html

Зауважте, що наприкінці цієї статті поставлене питання:

Тож коли слід використовувати енуми?

З відповіддю:

Будь-який час вам потрібен фіксований набір констант


21

Просто уникайте використання інтерфейсу:

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

public class NeddsConstant implements MyConstants {

}

Це заманливо, але порушує інкапсуляцію і розмиває відмінність визначень класів.


1
Дійсно, статичний імпорт є набагато кращим.
Аарон Маенпаа

1
Ця практика є дивним використанням інтерфейсів, які призначені для надання послуг, що надаються класом.
Рафа Ромеро

1
Я не погоджуюся з тим, щоб уникати використання інтерфейсу для констант, але ваш приклад, як я думаю, вводить в оману. Вам не потрібно реалізовувати інтерфейс, щоб отримати доступ до константи, оскільки він неявно статичний, загальнодоступний та остаточний. Отже, його простіше, ніж ви описали тут.
djangofan

Це правда ... це порушує інкапсуляцію, я вважаю за краще використовувати остаточний клас Constant, який виглядає більш об'єктно орієнтованим і кращим за інтерфейс АБО перерахуванням . Примітка: 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щоб отримати постійну. Це виглядає більш "об'єктно орієнтовано", як на мене.


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

Помилка номер один, яку ви можете зробити, - це створити глобально доступний клас, названий із загальною назвою, як-от Константи. Це просто засмічується сміттям, і ви втрачаєте всі можливості зрозуміти, яка частина вашої системи використовує ці константи.

Натомість константи повинні перейти до класу, який їм "належить". У вас є константа під назвою TIMEOUT? Ймовірно, він повинен перейти у ваш клас Communications () або Connection (). MAX_BAD_LOGINS_PER_HOUR? Переходить до користувача (). І так далі, і так далі.

Інше можливе використання - це файли Java .properties, коли "константи" можна визначити під час виконання, але не легко змінювати користувача. Ви можете їх упакувати у свої .jars та посилати їх на ресурс ClassLoader.


І звичайно, ви ніколи не хочете отримувати доступ до константи з більш ніж одного класу або не уникати безладу у верхній частині класу.
orbfish

6

Це правильний шлях.

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



5

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

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

Інша перевага полягає в тому, що для зміни константи не потрібно перекомпілювати все, що вона використовує. Коли ви посилаєтесь на статичне остаточне поле, значення цієї константи збирається у будь-який байт-код, на який посилається.


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

5

Я згоден, що використання інтерфейсу - це не шлях. Уникнення цього шаблону навіть має власний елемент (№18) в Ефективній Java на Bloch .

Аргумент, який висуває Блох проти постійного шаблону інтерфейсу, полягає в тому, що використання констант є детальною інформацією про реалізацію, але реалізація інтерфейсу для їх використання розкриває цю деталь реалізації у експортованому API.

The public|private static final TYPE NAME = VALUE;Модель є хорошим способом оголосити константу. Особисто я вважаю, що краще уникати створення окремого класу для розміщення всіх своїх констант, але я ніколи не бачив причин не робити цього, окрім особистих уподобань та стилю.

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

Якщо ви використовуєте версію раніше, ніж 1.5, ви все одно можете витягнути перерахування типів, використовуючи звичайні класи Java. (Детальніше про це див. На цьому веб-сайті ).


Деякі константи можуть використовуватися для виклику API. Наприклад, див. Інтерфейс org.springframework.transaction.TransactionDefinition. У ньому є список констант типу int PROPAGATION_REQUIRED = 0;
borjab

Я знаю, що це старе, але посилання на Ефективну Java Bloch порушена. Чи можете ви надати іншу чи іншу посилання, що підтверджує, що "використання інтерфейсу - це не шлях"?
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.wever). ІМХО, ти йдеш тут по бурхливій дорозі.
ToolmakerSteve

3

Хороший об’єктно-орієнтований дизайн не повинен мати багато загальнодоступних констант. Більшість констант повинні бути капсульовані в класі, який потребує їх для виконання своєї роботи.


1
Або вводиться в цей клас через конструктор.
ВВ.

2

Існує певна кількість думок, щоб відповісти на це. Для початку константи в Java зазвичай оголошуються загальнодоступними, статичними та остаточними. Нижче наведено причини:

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

2

Який найкращий спосіб впровадити константи на Java?

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

Створення інтерфейсу спеціально для декларування констант насправді найгірше: воно перемагає причину, через яку були розроблені інтерфейси: визначення методу (контракту).

Навіть якщо вже існує інтерфейс для задоволення конкретної потреби, декларування констант в них насправді не має сенсу, оскільки константи не повинні входити в API та контракт, що надається клієнтським класам.


Для спрощення ми маємо 4 дійсні підходи .

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

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

З Java 5 enum:

  • 2) оголошення enum у відповідному класі призначення (наприклад, як вкладений клас).
  • 2 варіант) створення enum як окремого класу (так визначено у власному файлі класу).

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

У більшості випадків шлях перерахування, ймовірно, тонший, ніж static final String/Integerспосіб, і особисто я вважаю, що цей static final String/Integerспосіб слід використовувати лише в тому випадку, якщо у нас є вагомі причини не використовувати переписки.
А щодо того, де нам слід оголошувати постійні значення, ідея полягає в пошуку, чи існує єдиний існуючий клас, який володіє специфічною і сильною функціональною згуртованістю з постійними значеннями. Якщо ми знайдемо такий клас, ми мусимо використовувати його як власника констант . В іншому випадку константа повинна бути пов'язана ні з одним конкретним класом.


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

Використання енумів - це дійсно спосіб, який слід серйозно розглянути.
Енуми мають велику перевагу перед Stringчи Integerпостійним полем.
Вони встановлюють більш сильне обмеження для компіляції. Якщо ви визначите метод, який приймає enum як параметр, ви можете передавати лише значення enum, визначене в класі enum (або null).
За допомогою 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, ... і на самому ділі не один з них не представляється більш доцільним провести перерахування.


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, значення тайм-ауту в секундах, ймовірно, повинно бути налаштуванням конфігурації (зчитування з файлу властивостей або через ін'єкцію, як навесні), а не постійним.


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там, де нам потрібна ця константа. Я думаю, що обидва однакові.


1
Це, по суті, є коментарем у відповідь на відповідь, яку дав bincob. Я думаю, що вони поводяться дуже схоже, але справа Бінкоба полягала в тому, що вони жодним чином не визначають інтерфейс. І пропозиція полягала в тому, щоб додати константи до реальних класів, а не створювати скелетний клас MyGlobalConstants. (Хоча це час від часу має сенс; використовуйте "статичний клас", маючи статичні константи та приватний конструктор для запобігання інстанції; див. Java.lang.math.) Подумайте про використання enum.
Джон Кумбс

Крім того, якщо "дефініція" в декларації класу запобігає підкласифікації. (У C # ви можете зробити "статичний", що означає "остаточний конспект", тому не потрібно явного приватного конструктора.)
Джон Кумбс

Так, @JonCoombs, але "остаточний" не перешкоджає прямому уявленню. І Java забороняє як кінцеві, так і абстрактні з'являтися разом для класів, отже, нескінченно з'являється приватний конструктор, щоб запобігти як інстанціюванню, так і підкласифікації. Я поняття не маю, чому "остаточний конспект" заборонений, окрім того, що він на перший погляд здається суперечливим у тому, як він читає: "Ви не можете підклас, але цей клас призначений для підкласу".

0

Я б не називав клас таким же (окрім корпусу), як постійний ... Я мав би як мінімум один клас "Налаштування", "Значення", або "Константи", де жили б усі константи. Якщо у мене їх велика кількість, я б згрупував їх у логічні постійні класи (UserSettings, AppSettings тощо).


Мені було заплановано заняття під назвою Константи, і це був лише невеликий приклад, який я знайшов.
мк.

0

Щоб зробити крок далі, ви можете розмістити в інтерфейсі глобально використовувані константи, щоб їх можна було використовувати в масштабах системи. Напр

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

Але тоді не реалізуйте це. Просто зверніться до них безпосередньо в коді через повністю кваліфіковане ім'я класу.


Справа в оголошенні їх в інтерфейсі (а не в його реалізації) полягає в тому, що ви можете пропустити "загальнодоступний статичний фінал".
Том Хотін - таклін

9
Інтерфейси призначені для визначення поведінкового контракту, а не зручності механізму утримання констант.
Джон Топлі

@JohnTopley Так, але це працює. ;)
trusktr

0

Для констант Enum - кращий вибір ІМХО. Ось приклад

публічний клас 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 }


}

0

Один із способів, як я це роблю, - це створити клас "Глобальний" з постійними значеннями та статично імпортувати в класи, які потребують доступу до константи.


0

static finalмоє вподобання, я б використовував лише те, enumякщо товар був справді численним.


0

я використовую static final для оголошення констант і переходжу з позначенням імен ALL_CAPS. Я бачив досить багато випадків реального життя, коли всі константи з'єднані в інтерфейс. Кілька постів справедливо назвали це поганою практикою, насамперед тому, що це не те, що інтерфейс. Інтерфейс повинен виконувати контракт і не повинен бути місцем для введення незв'язаних констант. Поміщення його в клас, який неможливо встановити (через приватний конструктор), також добре, якщо константна семантика не належить до конкретного класу ( ес). Я завжди ставлю константу в класі, до якої це найбільше стосується, тому що це має сенс і також легко піддається технічному обслуговуванню.

Енуми - хороший вибір для представлення діапазону значень, але якщо ви зберігаєте окремі константи з акцентом на абсолютне значення (наприклад, TIMEOUT = 100 мс), ви можете просто піти на static finalпідхід.


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 та уникати перешкод в Android, ця заміна в Android працює лише тоді, коли ви використовуєте невелику кількість полів. Це значна економія пам’яті, але може призвести до розростання, коли ви перебуваєте в інтерфейсі за полем у змішаному переліку. Наприклад, якщо у мене змішаний перелік, який визначає, що об'єкт бере в його конструкторі, я не можу нічого врятувати при такому підході, і я повернувся до не безпечних констант типу, тому що в Android не потрібно занадто багато періодів класів / інтерфейсів.
Droid Teahouse

0

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

Я нічого не читав Джошуа Блоха, так само

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

Як і в Біблійному фундаменталізмі, всі біблійні закони можна підсумувати

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

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

  • присвятіть себе основоположним нульовим основам усіма можливостями програми та розумом
  • і присвятіть досконалість своїх колег-програмістів, як би ви самі.

Також серед біблійних фундаменталістських кіл притягується сильна і розумна наслідки

  • Спочатку полюби себе. Тому що якщо ти не любиш себе сильно, то поняття "люби свого ближнього, як самого себе" не має великої ваги, оскільки "наскільки ти любиш себе" - це дата-рядок, над яким ти би любив інших.

Так само, якщо ви не поважаєте себе як програміста і просто приймаєте вимови та пророцтва якогось гуру-ната програмування БЕЗ сумнівів щодо основ, ваші цитати та покладання на Джошуа Блоха (тощо) не мають сенсу. А отже, ви насправді не поважали би своїх колег-програмістів.

Основні закони програмного програмування

  • лінь - чеснота хорошого програміста
  • ви повинні зробити своє програмування максимально легким, ледачим і, отже, максимально ефективним
  • ви повинні зробити наслідки та неприємності свого програмування максимально легкими, ледачими і, отже, максимально ефективними для своїх сусідських програмістів, які працюють з вами та збирають ваші програми програмування.

Константи інтерфейсу - це шкідлива звичка ???

За якими законами принципово ефективного та відповідального програмування підпадає цей релігійний едикт?

Просто прочитайте статтю wikipedia про константи шаблону інтерфейсу ( https://en.wikipedia.org/wiki/Constant_interface ), і нерозумно виправдовує це проти констант шаблону інтерфейсу.

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

    • Також - зачекайте другого прихильника мікрофункціонального програмування як засобу не потребує IDE. Зачекайте, поки ви прочитаєте моє пояснення щодо нормалізації моделі даних.
  • Забруднює простір імен змінними, які не використовуються в поточному діапазоні? Це можуть бути прихильники цієї думки

    • не обізнані та необхідність нормалізації моделі даних
  • Використання інтерфейсів для примусового виконання констант - це зловживання інтерфейсами. Прихильники таких мають погану звичку

    • не бачачи, що до "константи" слід ставитися як до контракту. І інтерфейси використовуються для забезпечення або проектування дотримання договору.
  • Важко, якщо не неможливо, в майбутньому перетворити інтерфейси в реалізовані класи. Га .... хммм ... ???

    • Чому ви хочете займатися такою схемою програмування, як ваша наполеглива життєдіяльність? IOW, навіщо присвячувати себе такій АМБІВАЛЕНТІ та поганій звичці програмування?

Якими б не були виправданнями, НІКОЛЬНО ВИМОЖЕНОГО ВИКЛЮЧЕННЯ, коли мова заходить про ОСОБЛИВО ЕФЕКТИВНУ програмну інженерію, щоб делегітимізувати або взагалі відмовити від використання констант інтерфейсу.

Не має значення, які були початкові наміри та психічні стани батьків-засновників, які створили Конституцію Сполучених Штатів. Ми могли б обговорити початкові наміри батьків-засновників, але мені все одно, що це письмові заяви Конституції США. І кожен громадянин США несе відповідальність за використання письмового літературного фундаменталізму, а не про неписані наміри Конституції США.

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

Основним є нормалізація моделі даних

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

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

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

Основним недоліком Е. Ф. Кодда та причиною його невідповідності ефективному людському розумінню є його переконання, що людські сприймані багатовимірні дані, що змінюються, можуть бути ефективно сприйняті через набір частинних двовимірних відображень.

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

Що Е. Ф. Кодд не зміг висловити.

У межах кожної узгодженої моделі даних це послідовний градуйований порядок узгодженості моделі даних для досягнення.

  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 - надзвичайно ефективний засіб, який дозволяє програмістам продовжувати свої шкідливі звички. Є кращі альтернативи, ніж осгі.

Або чому цього не зробити? Немає витоку приватних констант у опублікований контракт. Усі приватні константи повинні бути згруповані в приватний інтерфейс з назвою "Константи", тому що мені не хочеться шукати константи, і я лінивий багато разів вводити "приватний заключний рядок".

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;
  }
}

Єдине питання з константами інтерфейсу, що варто розглянути, - це коли інтерфейс реалізований.

Це не "первісний намір" інтерфейсів? Як би я піклувався про "первісний намір" батьків-засновників у розробці конституції США, а не про те, як Верховний Суд інтерпретуватиме письмові листи Конституції США ???

Адже я живу на землі вільної, дикої та домівки сміливих. Будьте сміливі, будьте вільні, будьте дикі - використовуйте інтерфейс. Якщо мої колеги-програмісти відмовляються використовувати ефективні та ледачі засоби програмування, я зобов’язаний золотим правилом знизити ефективність програмування, щоб відповідати їхнім? Можливо, і слід, але це не ідеальна ситуація.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.