Чи однозначні константи кращі за буквальні?


127

Я нещодавно зіткнувся з класом, який забезпечує майже кожен персонаж як постійний; все від COMMAдо BRACKET_OPEN. Цікаво, чи це потрібно; Я прочитав "статтю", яка говорить про те, що може бути корисним перетягнути однозначні букви в константи. Отже, я скептично ставлюсь.

Основне заклик використання констант полягає в тому, що вони мінімізують обслуговування, коли потрібні зміни. Але коли ми почнемо використовувати символ, інший ніж ',' для позначення коми?

Єдина причина, яку я бачу для використання констант замість літералів, - це зробити код більш читабельним. Але чи city + CharacterClass.COMMA + state(наприклад) насправді читабельніше, ніж city + ',' + state?

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


12
Дуже споріднений: programmers.stackexchange.com/questions/221034 / ...
Blrfl

33
Хм ... це може бути корисно для різних локалів, можливо? Наприклад, деякі мови використовують guillements (кутові лапки «та ») як лапки замість стандарту англійської мови "(або приємніше виглядати і ). Крім цього, це просто звучить як набір магічних персонажів. Якщо припустити два екземпляри CharacterClassвиклику englishCharsі frenchChars, можливо, це englishChars.LEFT_QUOTEможе бути , поки frenchChars.LEFT_QUOTEможе бути «.
Час Джастіна

4
У комах існує багато різних варіантів: en.wikipedia.org/wiki/Comma#Comma_variants - можливо, це не така глупа ідея, особливо якщо ваш вихідний код можна закодувати як utf-8.
Aaron Hall

21
У вашому випадку це як називати змінну "число". Ваша константа повинна була називатися DELIMITER. Або це повинно бути CITY_STATE = "{0}, {1}"
the_lotus

13
Ця стаття, яку ви пов’язали, дуже жахлива. Константи ніколи не слід кидати у відро таким. Поставте їх на класи, де у них є контекст: по суті, клас з константою забезпечує контекст, в якому використовується константа. Наприклад, Java File.separator. Клас повідомляє вам тип роздільника. Наявність класу з назвою Constsабо Constantsне містить контексту та ускладнює правильне використання констант.

Відповіді:


184

Тавтологія :

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

Здоровий глузд говорить вам про те, що const char UPPER_CASE_A = 'A';або const char A = 'A'не додає нічого, крім обслуговування та складності вашій системі. const char STATUS_CODE.ARRIVED = 'A'інший випадок.

Константи повинні представляти речі, незмінні під час виконання, але, можливо, їх потрібно буде в майбутньому змінити під час компіляції. Коли const char A =правильно рівне нічого, крім A?

Якщо ви бачите public static final char COLON = ':'код Java, знайдіть того, хто написав це, і зламайте їхні клавіатури. Якщо представництво на вас COLONколись зміниться, у :вас виникне кошмар на підтримку.

Опуднення:

Що станеться, коли хтось змінить його, COLON = '-'тому що там, де вони його використовують, потрібно -натомість скрізь? Чи збираєтесь ви писати одиничні тести, які в основному кажуть assertThat(':' == COLON)для кожної constпосилання, щоб переконатися, що вони не змінюються? Тільки, щоб хтось виправив тест, коли вони їх змінили?

Якщо хтось насправді стверджує, що public static final String EMPTY_STRING = "";це корисно і корисно, ви просто кваліфікували їх знання та сміливо ігноруєте їх у всьому іншому.

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

Згуртованість:

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

У комп'ютерному програмуванні згуртованість означає ступінь, до якого елементи модуля належать разом. Таким чином, згуртованість вимірює міцність взаємозв'язку між частинами функціональності в заданому модулі. Наприклад, у високо згуртованих системах функціональність сильно пов'язана.

З'єднання:

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

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

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

В дикій природі:

Нещодавно я відновив 1,000,000+ LOCпрограму, якій було 18 років. Були такі речі public static final COMMA = SPACE + "," + SPACE;. Це жодним чином не краще, ніж просто викласти " , "там, де це потрібно.

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

Він також ,визначав кілька разів з декількома неправильними написаннями слова COMMAв декількох пакунках і класах. З посиланнями на всі варіанти, змішані разом у коді. Нічого кошмару не було, ніж спробувати щось виправити, не порушуючи щось абсолютно не пов’язане між собою.

Те ж саме з алфавітом, було кілька UPPER_CASE_A, A, UPPER_A, A_UPPERщо більшу частину часу були рівні , A але в деяких випадках не було . Майже для кожного персонажа, але не для всіх персонажів.

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

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

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


112
Можливо, вам слід додати зразок контрприкладу: const char DELIMITER = ':'був би справді корисний.
Бергі

115
Я б зробив кілька аргументів, що EMPTY_STRINGвигідно. (1) Я можу набагато легше знайти всі способи використання EMPTY_STRINGфайлу, ніж я можу знайти всі способи використання "". (2) коли я бачу, EMPTY_STRINGя напевно знаю, що розробник задумав, що ця рядок буде порожньою, і що це неправильне редагування або заповнення для рядка для подачі пізніше. Тепер ви стверджуєте, що, висловлюючи цей аргумент, ви можете кваліфікувати мої знання і сміливо ігнорувати мене назавжди. Отже, як ви кваліфікуєте мої знання? А ви плануєте назавжди ігнорувати мою пораду? У мене немає жодного питання.
Ерік Ліпперт

39
@immibis: Ми можемо перестати думати про ці речі як про корисні в контексті управління змінами. Вони константи. Вони не змінюються. Подумайте про них як про корисні в контексті того, що люди шукають і розуміють семантику коду . Знання того, що щось є ключовим значенням-пара-роздільник, набагато корисніше, ніж знати, що це двокрапка; це факт про семантичну область проблеми програми, а не її синтаксису .
Ерік Ліпперт

15
@EricLippert: Я цікаве бачити точку інших тут , хто вказують на те , що єдина гарантія , що constзабезпечує те , що він не буде змінюватися під час виконання (після компіляції), хоча я згоден з вами , що смислове значення з constпоза набагато важливіше, ніж його використання в якості інструменту управління змінами. Зважаючи на це, я, безумовно, можу уявити собі те, const EARLIEST_OS_SUPPORTEDщо не тільки семантично відповідає, але і змінюватиметься з часом, коли програма розвиватиметься та видалятиме старий криптовалюта.
Роберт Харві

16
@DanielJour: Отже, це третій аргумент для EMPTY_STRING; що добре розроблена IDE буде поверхневими інструментами, які дозволять мені ставитись до цієї сутності символічно, а не синтаксично. Узагальнюйте це до четвертого аргументу: що бібліотека засобів аналізу коду, що сидить нижче IDE, може дозволити розширений програмний аналіз правильності коду на символічному рівні . Розробнику, який бажає скористатися інструментами, більш досконалими, ніж ті, написані буквально 40 років тому, потрібно лише внести невеликі зміни у свої звички для того, щоб отримати нагороди від сучасних інструментів.
Ерік Ліпперт

145

Основне заклик використання констант полягає в тому, що вони мінімізують обслуговування, коли потрібні зміни.

АБСОЛЮТНО НІ. Це зовсім не причина використання констант, оскільки константи не змінюються за визначенням . Якщо константа колись змінюється, то це не була константа, чи не так?

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

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

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


42
Хоча я погоджуюся з духом того, що ви тут говорите, ваше друге / третє речення насправді не є правильним. Константа може змінюватися між версіями файлу. Насправді більшість програм, які я пишу, мають постійну назву на зразок чогось MY_VER, що містить номер поточної версії програми, який потім може бути використаний протягом усієї залишку програми, а не магічний рядок типу "5.03.427.0038". Додатковою перевагою є те, що ви говорите, що вона надає семантичну інформацію.
Monty Harder

50
Справедливо кажучи, суть константи полягає в тому, що вона не змінюється під час виконання після ініціалізації, не те, що вона не змінюється між компіляціями. З точки зору компілятора, справа полягає в тому, що компілятор може робити припущення, що програма не може його змінити; чи дозволено програмісту змінювати його під час перекомпіляції, це не змінює його постійної ності. Можуть також бути випадки, коли програмне забезпечення приймає значення апаратного забезпечення лише для читання, можливо, шляхом перенаправлення const volatile T*покажчика на заздалегідь задану адресу; хоча програма не може її змінити, апаратне забезпечення може.
Час Джастіна

6
@MontyHarder: Добрий момент. Мою думку підтверджує той факт, що я, як правило, використовую мови, які розрізняють константи - які завжди повинні бути незмінними - і змінні, які можуть бути призначені один раз - які можуть змінюватися від версії до версії, запускати до запуску чи будь-що інше. Постійна і змінна - це різні речі; одна залишається такою ж, а одна змінюється з часом.
Ерік Ліпперт

7
@SteveCox: Я згоден; те, як C / C ++ характеризують "const", дивно і обмежено. Я хочу мати константи - це те, що їх значення не змінюються, не те, що я обмежую їх зміни в одних функціях, а не в інших.
Ерік Ліпперт

15
"Це зовсім не причина використання констант, оскільки константи не змінюються за визначенням. Якщо константа коли-небудь змінюється, то вона не була константою, чи не так?" Зміна констант під час компіляції (очевидно, не час виконання) цілком нормально. Тому ви в першу чергу зробили їх чітко позначеною "річчю". Звичайно, постійні ОП є небажаними, але думають , що - щось на зразок const VERSION='3.1.2'або const KEYSIZE=1024чи будь-яких інших .
AnoE

61

Ні, це німе.

Що НЕ обов'язково німий витягати такі речі , як , що в названі етикетки з причин локалізації. Наприклад, роздільник тисячі - це кома в Америці (1 000 000), але не кома в інших регіонах. Потягнувши це на названий ярлик (з відповідним ім'ям без коми), програміст може ігнорувати / абстрагувати ці деталі.

Але робити постійною, тому що "магічні струни погані" - це просто вантаж.


8
Локалізація зазвичай складніше, ніж просто рядкові константи. Наприклад, деякі мови хочуть роздільник списку між усіма елементами списку, а інші виключають роздільник перед останнім елементом. Отже, зазвичай потрібні не локалізовані константи, а локалізовані правила .
Влад

19
Насправді розмежувач тисяч необов'язково є обмежувачем тисяч в інших регіонах (Китай / Японія). Він навіть не встановлюється після постійної кількості цифр (Індія). О, і можуть бути різні роздільники, залежно від того, чи є це розділювач 1000 або роздільник 1000000 (Мексика). Але це менше проблеми, ніж використання цифр ASCII 0-9 в деяких регіонах (Farsi). ux.stackexchange.com/questions/23667/…
Пітер

1
@Vlad Локалізація набагато складніша за це, однак, роздільник тисяч - це добре відомий приклад, який люди впізнають.

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

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

29

Є кілька символів, які можуть бути неоднозначними або використовуватися для декількох різних цілей. Наприклад, ми використовуємо '-'дефіс, знак мінус або навіть тире. Ви можете зробити окремі імена як:

static const wchar_t HYPHEN = '-';
static const wchar_t MINUS = '-';
static const wchar_t EM_DASH = '-';

Пізніше ви можете змінити код, щоб він не розмежувався, перезначивши їх як:

static const wchar_t HYPHEN = '-';
static const wchar_t MINUS = '\u2122';
static const wchar_t EM_DASH = '\u2014';

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

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


Для мене це єдина поважна причина, з якої можна створити символьні константи
FP

2
Використання -в якості дефісу є досить оманливим ... це вкрай коротше для більшості шрифтів. (Це навіть коротше, ніж на штрих.)
Paŭlo Ebermann

Гаразд, не найкращий приклад. Я почав із strings, а wchar_tскористався стандартним конвенцією рукопису "--"для тире. Але в первинному прикладі було використання одиночних символів, тому я перейшов, щоб залишатися вірним питанню. Є люди, які -набирають тире, особливо коли вони працюють зі шрифтом із фіксованим тоном.
Адріан Маккарті

1
@ PaŭloEbermann Ні, традиційно em dash - це ширина символу 'm' шрифту, а en dash - ширина символу 'n'.
Дізлі

@Dizzley так, і ширина дефісів <n-ширина <м-ширина.
Paŭlo Ebermann

22

Постійна повинна додавати значення.

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

Якщо ви використовуєте кому для певної мети і хочете використовувати названу константу, назвіть її після її призначення. Приклад:

  • city + CharacterClass.COMMA + state = погано
  • city + CITY_STATE_DELIMITER + state = хороший

Використовуйте функції для форматування

Мені особисто більше подобається FormatCityState(city, state)і мені все одно, як виглядає тіло цієї функції, поки воно коротке і проходить тестові випадки.


1
Ах, але кома - це не завжди одна і та сама кома. Я міг би визначити COMMA = '\ u0559' або '\ u060C' тощо (див. Unicode) або навіть перетворити його в змінну пізніше і прочитати її з конфігураційного файла. Таким чином, він все одно матиме те саме значення , але просто інше значення. Як щодо цього.
Містер Лістер

2
@MrLister: YAGNI. Якщо у вас є така потреба: чудово! У вас прекрасне рішення. Але якщо ви цього не зробите - не захаращуйте свій код, тому що, можливо, ви можете одного дня. Крім того, з мого досвіду, якщо ви намагаєтеся ввести абстракції без функції у вашій кодовій базі, люди не дуже здатні бути послідовними. Отже, навіть якщо ви визначили COMMA з наміром використовувати якусь іншу кодову точку, в програмі достатнього розміру та віку, щоб вибір взагалі був важливим, ви, ймовірно, виявите, що константа не використовувалася всюди, де вона мала бути були (і навпаки, можуть бути використані також недоречно).
Еймон Нербонна

17

Ідея про те, що постійний COMMA кращий ','або ","досить легкий для розвінчання. Звичайно, є випадки, коли це має сенс, наприклад, final String QUOTE = "\"";значно економлять на читанні без усіх косих рис, але символи, що контролюють мову заборони, як, \ 'і "я не вважаю їх дуже корисними.

Використання final String COMMA = ","- це не тільки погана форма, це небезпечно! Коли хтось хоче змінити роздільник ","на, ";"він може піти змінити файл констант, COMMA = ";"оскільки це швидше це зробити, і він просто працює. Крім того, ви знаєте, всі інші речі, які використовували COMMA зараз, також є крапками з комою, включаючи речі, надіслані зовнішнім споживачам. Таким чином, він проходить усі ваші тести (тому що весь код маршалування та демарширування також використовував COMMA), але зовнішні тести не зможуть.

Що корисно - це дати їм корисні імена. І так, іноді кілька констант матимуть однаковий вміст, але різні назви. Наприклад final String LIST_SEPARATOR = ",".

Таким чином, ваше запитання: "чи є єдині константи char краще, ніж букви", і відповідь нерівнозначно "ні", вони ні. Але навіть краще, ніж обидва ці, це вузькообласне ім'я змінної, яке прямо говорить, яка її мета. Звичайно, ви витратите кілька додаткових байт на ці додаткові довідки (якщо припустимо, що вони не будуть складені на вас, що, напевно, буде), але в довгостроковому обслуговуванні, саме там більша частина вартості програми, вони варті того часу, щоб зробити.


Як щодо умовного визначення DISP_APOSTROPHE як ASCII 0x27 або символу єдиного правого цитата Unicode (що є більш типографічно викладеним апострофом), залежно від цільової платформи?
supercat

3
насправді QUOTEприклад доводить, що це погана ідея, оскільки ви привласнюєте її до того, що загалом / в народі відомо як « DOUBLE QUOTEі» QUOTEозначає, SINGLE_QUOTEщо більш правильно називається APOSTROPHE.

3
@JarrodRoberson Я не відчуваю, що цитата особисто передбачає єдину цитату - але це ще одна вагома причина усунути двозначність, де можна!
corsiKa

2
Мені не подобається QUOTEприклад з додаткової причини - це робить читання рядків, побудованих з ним, ще складніше, "Hello, my name is " + QUOTE + "My Name" + QUOTEце тривіальний приклад, і все ж він виглядає погано. О, звичайно, замість конкатенації ви можете використовувати жетони заміни, теж "Hello, my name is %sMy Name%s".format(QUOTE, QUOTE)може бути гірше. Але, ей, давайте спробуємо індексовані жетони "Hello, my name is {0}My Name{0}".format(QUOTE)тьфу, не так вже й краще. Будь-яка нетривіальна рядок, породжена цитатами, була б ще гіршою.
ВЛАЗ

2
@corsiKa - Я буду жити з уникнутими фактичними котируваннями. Якщо я пропуститиму одну, IDE, яку я використовую, негайно скаржиться. Код, швидше за все, також не складеться. Це досить легко помітити. Як легко зробити помилку, роблячи, "My name is" + QUOTE + "My Name" + QUOTEя насправді зробив ту саму помилку тричі, написавши вищевказаний коментар. Ви можете це помітити? Якщо це займе у вас небагато, це пропущений простір після є . Ви форматуєте рядок? У такому випадку рядок з декількома лексемами для заміни стане ще гіршим. Як я можу використовувати його, щоб він був більш читабельним?
ВЛАЗ

3

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

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

Я можу придумати ще кілька поодиноких випадків, коли могло б мати сенс використовувати константи замість відповідних літералів. Наприклад, ви можете вказати, що NEWLINE є буквальним '\ n' у вікні Unix, але '\ r \ n' або '\ n \ r', якщо ви знаходитесь у вікні Windows або Mac. Те саме стосується розбору файлів, які представляють табличні дані; Ви можете визначити константи FIELDSEPARATOR та RECORDSEPARATOR. У цих випадках ви фактично визначаєте константу для представлення символу, який виконує певну функцію. Тим не менш, якби ти був початківцем програмістом, можливо, ти назвав би свій роздільник поля постійним COMMA, не розуміючи, що ти повинен був би назвати його FIELDSEPARATOR, і до того часу, як ти зрозумів, код буде вироблятися, і ти будеш наступним проект,

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

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


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

3

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

Хороші абстракції роблять код простим у використанні, з одного боку, та легким у підтримці, з іншого.

Я повністю погоджуюсь, що саме DELIMITER=':'по собі є поганою абстракцією, і лише кращою, ніж COLON=':'(оскільки остання збідніла).

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

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

Основне заклик використання констант полягає в тому, що вони мінімізують обслуговування, коли потрібні зміни.

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


2

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

В обох випадках використання названого символу подібне COMMAдопомагає забезпечити згуртованість інакше нерозбірного продукту. Ця величина часто може перевищувати вартість надмірно багатослівних позначень.


2

Зауважте, що ви намагаєтесь скласти список.

Отже, переробляйте це як: String makeList(String[] items)

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


0

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

Однак є щонайменше два випадки, коли має сенс оголошувати константи, ім'я яких точно описує їх зміст, і де ви не можете змінити значення без належної зміни назви константи:

  • Математичні чи фізичні константи, наприклад PI = 3.14159. Тут роль константи полягає в тому, щоб діяти як мнемонічне, оскільки символічне ім'я PIнабагато коротше і читабельніше, ніж значення, яке воно представляє.
  • Вичерпні списки символів в аналізаторі або клавішах на клавіатурі. Можливо, навіть є сенс скласти список констант з більшістю або всіма символами Unicode, і саме тут може потрапити ваш випадок. Деякі символи, такі як Aочевидні та чітко впізнавані. Але чи можна легко розказати Аі Aрозставити? Перший кирилична буква А , а остання латинська буква А . Це різні букви, представлені різними кодовими точками Unicode, хоча графічно вони майже однакові. Я вважаю за краще константи CYRILLIC_CAPITAL_AіLATIN_CAPITAL_Aв моєму коді, ніж два майже однакових на вигляд символи. Звичайно, це безглуздо, якщо ви знаєте, що будете працювати лише з символами ASCII, які не містять кирилиці. Так само: я використовую латинський алфавіт щодня, тому якби писав програму, яка потребувала китайського символу, я, мабуть, вважаю за краще використовувати константу, а не вставляти символи, які я не розумію. Для тих, хто щодня використовує китайські символи, китайський символ може бути очевидним, але латинський може бути легше представити як названу константу. Отже, як бачите, це залежить від контексту. Тим не менш, бібліотека може містити символічні константи для всіх символів, оскільки автори не можуть заздалегідь знати, як бібліотека буде використовуватися та яким символам можуть знадобитися константи для поліпшення читабельності в певній програмі.

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


-1

Може бути.

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

city + '.' + state

тоді як це порівняно важка помилка

city + Const.PERIOD + state

Залежно від вашого інтернаціоналізації та глобалізації, різниця між апострофом ASCII та відкритим і закритим апострофом Windows-1252 (або подвійною цитатою ASCII та подвійною цитатою Windows-1252, відкритою та закритою подвійною цитатою) може бути суттєвою і, як відомо, важко візуалізувати погляд за кодом.

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

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


2
що відбувається, коли якийсь дебіл змінюється Const.PERIODрівним ~? Не існує виправдання для тавтології названих символів, вона просто додає технічного обслуговування та складності, які не потребують сучасних середовищах програмування. Чи збираєтесь ви написати набір одиничних тестів, які в основному говорять assert(Const.PERIOD == '.')?

3
@JarrodRoberson - Це б смоктало, звичайно. Але у вас виникне стільки ж проблем, якби хтось додав константу Unicode, яка виглядає майже як кома, а не фактична кома. Як я вже говорив, це не та річ, яку я б робив у проекті розвитку «зеленого поля». Але якщо у вас є застаріла база коду з плямистим тестовим набором, де ви кілька разів стикалися з комою / періодом або апострофом / Microsoft, гидота апострофи видає кілька разів, створюючи деякі константи і говорячи людям використовувати їх, може бути розумним способом зробити код краще, не витрачаючи рік на тести.
Джастін Печера

3
Ваш старий приклад - поганий, я щойно закінчив рефакторинг на 1000 000+ баз коду LOC, якому виповнилося 18 років. У ньому кожен певний символ визначався так, як це багато разів, навіть з різними конфліктуючими іменами. І багато разів речі, названі COMMAфактично, встановлювалися = SPACE + "," + SPACE. Так, якийсь ідіот мав SPACEпостій. Я відремонтував їх ВСЕ, і код був на порядок більш читабельним, а наймачі коледжів були набагато більш здатні відстежувати речі та виправляти їх, не маючи 6 рівнів непрямості, щоб дізнатися, що щось насправді встановлено.

-1

Чи однозначні константи кращі за буквальні?

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

Константи забезпечують:

  • семантика
  • зміни, під час розвитку
  • непрямість

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

Буквальне і константне може змінюватися і під час розвитку. Це те, що викликає питання про магічне число. Струни можуть бути і магічними числами.

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

Непрямий спосіб може вирішити будь-яку проблему, крім сильної непрямості.

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

Непрямістю можна переборщити. Деякі вважають за краще шукати та замінювати літерали для внесення змін. Це добре, якщо 42 явно є сенсом життя, а не змішується разом з 42, атомним числом молібдену.

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


1
Семантичний - ключ. Якщо і "A" має більше семантичного значення, ніж просто бути "A", то це ж семантичне значення слід прив'язати до тієї ж "посилання". Не має значення, чи це константа чи ні. Я цілком погоджуюся.
oopexpert

-1

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

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

Г. К. Честертон, М'яч і Хрест

Немає нічого поганого в оцінці істини, і немає нічого поганого в тому, щоб заявити правду, особливо коли говорити з комп'ютером.

Якщо ти брешеш за комп’ютером, він отримає тебе

Перрі Фаррар - Германтаун, штат Меріленд (від More Pearls of Programming)


Але здебільшого я згоден з людьми, які кажуть, що це німо. Я занадто молодий, щоб навчитися програмувати FORTRAN, але чув, як можна сказати, що ви можете переосмислитись 'A' = 'Q'і придумати всілякі чудові криптограми. Ви цього не робите.

Поруч із проблемами i18n, які виникали раніше (які не переосмислюють гліф "COMMA", а справді переосмислюють гліф DECIMAL_POINT). Побудова французьких морквяних цитат або британських одинарних цитат для того, щоб передати зміст людині, є справді, і вони дійсно повинні бути змінними, а не константами. Постійна була б AMERICAN_COMMA := ','іcomma := AMERICAN_COMMA

І, якби я використовував шаблон побудови для побудови SQL-запиту, я б швидше побачив

sb.append("insert into ")
 .append(table_name)
 .append(" values ")
 .append(" ( ")
 .append(val_1)
 .append(",")
 .append(val_2)
 .append(" ); ")

ніж будь-яка інша річ, але якби ви збиралися додавати константи, це було б

INSERT_VALUES_START = " ( "
INSERT_VALUES_END = " ) "
INSERT_VALUES_SEPARATOR = " , "
QUERY_TERMINATOR = ";"

sb.append("insert into ")
 .append(table_name)
 .append(" values ")
 .append(INSERT_VALUES_START)
 .append(val_1)
 .append(INSERT_VALUES_SEPARATOR)
 .append(val_2)
 .append(INSERT_VALUES_END)
 .append(QUERY_TERMINATOR)

Однак якщо ви коли-небудь дивилися, щоб хтось інший програмував (або вводив), ви можете помітити цікаві химерності. Не всі ми зоряні машиністки. Багато хто з нас запізнювались на програмування або піднімалися за допомогою радянських клавіатур (де клавіші вводяться на вас), і ми любимо вирізати та вставляти окремі літери, а не намагатися знайти їх на клавіатурі та / або покладатися на автозаповнення.

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


Ще одна річ, яку слід пам’ятати про рядкові літерали - це спосіб їх складання. Принаймні, у Delphi (яка є єдиною мовою, якою я одержима над стеком), ви заведете ваші буквари, що вискакували в стек кожної функції. Отже, багато літералів = багато функцій накладних витрат; "," у function_A - це не той самий біт пам'яті, як "," у function_B ". Для боротьби з цим існує" рядок ресурсів ", який можна побудувати і пов'язати в бік - і ось так вони роблять речі i18n (вбивство дві птахи з одним кущем). У Python усі ваші рядкові букви є об’єктами, і це насправді може здатися корисним utils.constants.COMMA.join(["some","happy","array","strings"]), але це не зоряна ідея для пунктів, що повторюються знову і знову на цій сторінці.


-4

Але коли ми почнемо використовувати символ, інший ніж ',' для позначення коми?

Для локалізації.

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

Тож є можливість зробити константи DECIMAL_POINT та COMMA, якщо ви робите глобалізацію.


2
Але тоді COMMA та DECIMAL_POINT не є правильними іменами для сутностей (тому, ймовірно, тому ви поступили з відмови).
Кайл Странд

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