Це погана практика мати інтерфейс для визначення констант?


40

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

Переваги, які я бачу, є:

  • простий доступ до констант: MY_CONSTANTзамістьThatClass.MY_CONSTANT
  • кожна константа визначається лише один раз

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

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


Відповідь "Неправильна практика, щоб інтерфейс визначав X?", Оскільки це X, що не є "методом підписів", майже завжди напевно є "Так".
Т. Сар - Відновіть Моніку

Відповіді:


79

Джошуа Блох радить проти цього у своїй книзі « Ефективна Java» :

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

Такий же ефект можна отримати і з звичайним класом, який визначає константи, а потім використовувати import static com.example.Constants.*;


13

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

Константи SOMETIMES - це деталі реалізації. НЕЩО вони не є. Як завжди, інженеру потрібно використовувати свій мозок, щоб вирішити, що робити, а не покладатися на обмірну схему чи практику.


7

Я не думаю, що добре мати інтерфейси лише для констант.

Але якщо інтерфейс, який визначає поведінку (методи впровадження класів повинні реалізовуватися), має константи, це нормально. Якщо він "просочує деякі деталі про реалізатор" в API, це так і має бути. Вони також просочуються тим, що реалізатор реалізує методи foo та bar.

Візьмемо для прикладу інтерфейс java.awt.Transparency. Він має константи OPAQUE, BITMASK і TRANSLUCENT, але також має метод getTransparency ().

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


2

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


1
інтерфейси - це державні договори. Постійні ЗНАЧЕННЯ - це питання приватного характеру, публічний інтерфейс повинен максимум викривати їх імена. Це найкраще залишити для абстрактного класу.
jwenting

Випадки: javax.naming.Context, javax.ims.Session та сотні таких інтерфейсів ...
CMR

2
@jwenting Також чи міг би бути відкритий інтерфейс "at most expose their names", не піддаючи значенням?
CMR

це залежатиме від мови програмування, я думаю. У випадку з Java, ні.
jwenting

2

Компанія, в якій я працював, широко використовувала 1- константи, імпортовані інтерфейсом . Я не відчуваю жодної шкоди від цього.

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

Класна річ інтерфейсів - це те, що ви отримуєте перевагу працювати в будь-якому випадку - введіть всі потрібні простори імен або жодне з них (і отримуйте доступ до них явно, за допомогою MyInterface.CONSTANT). Приблизно те саме, що import static MyInterface.*, але трохи очевидніше.


1: Якщо ви не знайомі з Java, я не маю на увазі importключове слово, я просто маю на увазі черезimplements MyConstantsInterface


1

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

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

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

Для отримання більш технічного посібника: download.oracle.com/javase/1.5.0/docs/guide/language/static-import.html


Додавання додаткових посилань, що посилаються на статичний імпорт (1.5): 1. Вікіпедія 2. Документи Oracle з посиланням на @Justinc
Abhijeet

1
So when should you use static import? Very sparingly! Only use it when you'd otherwise be tempted to declare local copies of constants, or to abuse inheritance (the Constant Interface Antipattern). In other words, use it when you require frequent access to static members from one or two classes. If you overuse the static import feature, it can make your program unreadable and unmaintainable, polluting its namespace with all the static members you import. Довідка з Документів Oracle
Абхієет

1

Ні, це не загальна погана практика.

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

Використання синтаксису лише тому, що ви можете, це справжня проблема.

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