Використання вкладених громадських занять для організації констант


21

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

public static final String CREDITCARD_ACTION_SUBMITDATA = "6767";
public static final String CREDITCARD_UIFIELDID_CARDHOLDER_NAME = "3959854";
public static final String CREDITCARD_UIFIELDID_EXPIRY_MONTH = "3524";
public static final String CREDITCARD_UIFIELDID_ACCOUNT_ID = "3524";
...
public static final String BANKPAYMENT_UIFIELDID_ACCOUNT_ID = "9987";

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

public class IntegrationSystemConstants
{
    public class CreditCard
    {
        public static final String UI_EXPIRY_MONTH = "3524";
        public static final String UI_ACCOUNT_ID = "3524";
        ...
    }
    public class BankAccount
    {
        public static final String UI_ACCOUNT_ID = "9987";
        ...
    }
}

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


1
Мені швидше подобається ідея. Мені здалося, що я роблю щось подібне в C ++, коли мені хотілося, щоб у C # -style були схожі на обстеження та поведінку, але зі значущими значеннями (я думаю, що ідея виникла тому, що я звик використовувати класи випадків замість перерахунків у Scala). Зрозуміло, це був особистий проект для розваги, а не зусиль команди.
KChaloux

Відповіді:


13

Я не згоден з жодною з двох пропозицій.

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

Не повинно бути лише констант класів / інтерфейсів.

Клас CreditCard(не внутрішній клас) повинен існувати. Цей клас / інтерфейс має методи відносно кредитних карт, а також констант UI_EXPIRY_MONTHта UI_ACCOUNT_ID.

Там повинен існувати клас / інтерфейс BankAccount(не внутрішній клас). Цей клас / інтерфейс має методи відносно банківських рахунків, а також постійні UI_ACCOUNT_ID.

Наприклад, в Java API кожен клас / інтерфейс має свої константи. Вони не перебувають у класі / інтерфейсі Константи із сотнями констант, або групуються у внутрішні класи, або ні.

Наприклад, ці константи, що відносяться до наборів результатів, знаходяться в інтерфейсі ResultSet:

static int  CLOSE_CURSORS_AT_COMMIT 
static int  CONCUR_READ_ONLY 
static int  CONCUR_UPDATABLE 
static int  FETCH_FORWARD 
static int  FETCH_REVERSE 
static int  FETCH_UNKNOWN 
static int  HOLD_CURSORS_OVER_COMMIT 
static int  TYPE_FORWARD_ONLY 
static int  TYPE_SCROLL_INSENSITIVE 
static int  TYPE_SCROLL_SENSITIVE 

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

Ці константи, що стосуються дій інтерфейсу, знаходяться в інтерфейсі javax.swing.Action:

static String   ACCELERATOR_KEY 
static String   ACTION_COMMAND_KEY 
static String   DEFAULT 
static String   LONG_DESCRIPTION 
static String   MNEMONIC_KEY 
static String   NAME 
static String   SHORT_DESCRIPTION 
static String   SMALL_ICON 

Класи, що реалізують, мають поведінку відносно дій інтерфейсу, вони не є просто постійними власниками.

Я знаю принаймні один інтерфейс "константи" ( SwingConstants) без методів, але у нього немає сотні констант, лише кілька, і всі вони пов'язані з напрямками та положеннями елементів інтерфейсу:

static int  BOTTOM 
static int  CENTER 
static int  EAST 
static int  HORIZONTAL 
static int  LEADING 
static int  LEFT 
static int  NEXT 
static int  NORTH 
static int  NORTH_EAST 
static int  NORTH_WEST 
static int  PREVIOUS 
static int  RIGHT 
static int  SOUTH 
static int  SOUTH_EAST 
static int  SOUTH_WEST 
static int  TOP 
static int  TRAILING 
static int  VERTICAL 
static int  WEST 

Я думаю, що константи лише класів не є хорошим дизайном ОО.


1
Хоча я згоден, що константи лише класів у більшості випадків є ознакою поганого дизайну, є законне використання. Наприклад, константа не завжди "належить" до певного класу. Клавіші для додаткових додатків в програмуванні Android - один з таких конкретних прикладів.
цікавотехніка

1
+1, але константи користувальницького інтерфейсу, ймовірно, не повинні бути у таких бізнес-моделях, як BankAccount. Вони належать до якогось класу інтерфейсу користувача.
кевін клайн

10

з'ясувалося, що константи занадто розсіяні і їх слід організувати в єдиний файл "головних" констант.

Це 100% неправильне рішення проблеми констант, які "важко знайти". Принципова помилка (на жаль, занадто часто вчиняється програмістами) групувати речі за технічними критеріями, такими як константи, перерахунки чи інтерфейси.

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

Крім того, один величезний файл констант вбиває швидкість розвитку Java, оскільки константи вбудовані в класи, які використовують їх під час компіляції, тому будь-яка зміна примушує перекомпіляцію всіх цих файлів і всього, що від них залежить. Якщо у вас є один файл із константами, який використовується скрізь, ви значною мірою втрачаєте перевагу поступової компіляції: спостерігайте за тим, як Eclipse блокується протягом 15 хвилин, оскільки він перекомпілює весь ваш проект для кожної зміни у цей файл. А оскільки цей файл містить усі постійні, які використовуються в будь-якому місці, ви будете змінювати його досить часто. Так, я кажу з особистого досвіду.


Мені не було відомо про потенційний вплив на середовище розробки, і я думаю, що вкладений підхід до класу не дуже допоможе в цьому, правда?
FrustratedWithFormsDesigner

1
@FrustratedWithFormsDesigner: Це залежить від того, скільки зусиль витрачає механізм поступового складання на моделювання залежностей.
Майкл Боргвардт

9

Ти правий. Ваша пропозиція дозволяє програмісту import static Constants.BankAccount.*і усунути незліченну кількість повторень "BANKACCOUNT_". Конкатенація - це поганий замінник фактичного масштабування. Однак, я не сподіваюся на те, що ти зміниш культуру команди. Вони мають уявлення про належну практику і, швидше за все, не зміниться, навіть якщо ви покажете їм 100 експертів, які кажуть, що вони неправильні.

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


На даний момент у нас є один файл констант, який містить більшість констант ідентифікатора поля UI, та кілька інших файлів констант, які залежать від підпроекту. Але тепер, константи, що стосуються підпроекту, потребують використання інших пов'язаних підпроектів, тому саме спонукало ідея об'єднати їх у один файл «головних» констант. Що краще, ніж зараз, тому що іноді я навіть не знаю, які константи подають файл для значення, а хтось інший створив дублікат константи, оскільки не міг знайти його в іншому файлі констант підпроекту.
FrustratedWithFormsDesigner

8
Клас констант, який постійно змінюється ... є щось дзен, якщо ви копаєте досить важко.
KChaloux

2
@FrustratedWithFormsDesigner: ідентифікатори поля інтерфейсу? Не знаєте, де знайти цінність? Звучить, як величезна купа WTF. Ви маєте моє співчуття.
Кевін Клайн

6

Обидва підходи працюють, і ось що важливо наприкінці дня.

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


Для досить тривалого списку констант я б навіть віддав перевагу постійним інтерфейсам над тим, щоб їх було все в одному класі. Небезпечно вибрати неправильний варіант із автоматичного завершення. Звичайно, це залежить від того, наскільки досить довго :)
Горан Йович

1
@GoranJovic Ну, кожен анти-шаблон є корисним певним чином (або, принаймні, зручним), він би не став зразком, якби не був.
янніс

1

Одне з викликів довгого списку констант - пошук «правильної» константи, яку слід використовувати. Незмінно, хтось приймає константу в кінці рядка, а не додає його до групи, до якої він належав.

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

Якщо що-небудь, ваша пропозиція допомагає відмовити в застосуванні "неправильної" константи, навіть якщо вона може підходити до конкретної ситуації. Обгортаючи константи в репрезентативному класі, це спонукає розробників задуматися, чи варто їм користуватися. Наприклад, якщо я потягнувся CreditCard.SomeConstantза загальне використання, мені справді слід задуматися, чому General.SomeConstantнатомість не існує такої ситуації.

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


1

Я роблю це періодично (у C #), особливо якщо мені потрібно запрограмувати проти / проаналізувати добре відому та виправлену XML-структуру чи щось подібне вкладене та рядкове важке ... наприклад, спеціальний аналізатор блоку конфігурації.

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

Це дуже легко програмувати на відповідний Xml.

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