Відповіді:
Вміщення статичних членів в інтерфейс (і реалізація цього інтерфейсу) є поганою практикою, і навіть існує його назва, постійний інтерфейс Antipattern , див. Ефективна Java , пункт 17:
Постійна схема інтерфейсу - це погане використання інтерфейсів . Те, що клас використовує деякі константи внутрішньо, є деталлю реалізації. Реалізація постійного інтерфейсу змушує цю деталь реалізації просочитися до експортованого API класу. Для користувачів класу не має жодних наслідків, що клас реалізує постійний інтерфейс. Насправді це може навіть збити з пантелику. Гірше, що це означає зобов'язання: якщо в майбутньому випуску клас буде змінено так, що йому більше не потрібно використовувати константи, він все одно повинен реалізувати інтерфейс для забезпечення бінарної сумісності. Якщо нефінальний клас реалізує постійний інтерфейс, усі його підкласи матимуть свої простори імен, забруднені константами в інтерфейсі.
У бібліотеках платформи java є кілька постійних інтерфейсів, таких як
java.io.ObjectStreamConstants
. Ці інтерфейси слід розглядати як аномалії та не слід імітувати.
Щоб уникнути деяких підводних каменів постійного інтерфейсу (оскільки ви не можете заважати людям реалізовувати його), слід віддавати перевагу належному класу з приватним конструктором (наприклад, запозичений у Вікіпедії ):
public final class Constants {
private Constants() {
// restrict instantiation
}
public static final double PI = 3.14159;
public static final double PLANCK_CONSTANT = 6.62606896e-34;
}
А щоб отримати доступ до констант, не вимагаючи їх повною мірою (тобто без префіксації їх імені класу), використовуйте статичний імпорт (починаючи з Java 5):
import static Constants.PLANCK_CONSTANT;
import static Constants.PI;
public class Calculations {
public double getReducedPlanckConstant() {
return PLANCK_CONSTANT / (2 * PI);
}
}
" Постійна схема інтерфейсу - це погане використання інтерфейсів "
Хто б не придумав цю гіпотезу, як би не був гуру, він придумав її на основі необхідності продовжувати ефективно застосовувати шкідливі звички та практики. Гіпотеза базується на просуванні обґрунтованості звичних шкідливих звичок програмного забезпечення.
Я написав тут спростування відповіді на цю гіпотезу: Який найкращий спосіб впровадити константи на Java? пояснення безпідставності цієї гіпотези.
Протягом 10 років це питання залишалося відкритим, поки воно не було закрито протягом 2 годин після того, як я виклав мотиви, що виправдовують цю гіпотезу, тим самим викриваючи НЕБЕЗПЕЧНІСТЬ до дискусій з боку тих, хто дорого тримається цієї помилкової гіпотези.
Це моменти, які я висловив проти гіпотези
Основою для проведення цієї гіпотези є необхідність в методах та правилах RESTRICTIVE для подолання наслідків шкідливих програмних звичок та методологій.
Прихильники настроїв " Постійна схема інтерфейсу - це погане використання інтерфейсів" не в змозі надати будь-яких причин, крім тих, що були викликані необхідністю впоратися з наслідками цих шкідливих звичок та практики.
Вирішіть принципове питання.
І тоді, чому б не повною мірою використовувати та не використовувати кожну мовну особливість мовної структури Java для власної зручності. Куртки не потрібні. Навіщо вигадувати правила, які забарикадують ваш неефективний спосіб життя, щоб дискримінувати та інкримінувати більш ефективний спосіб життя?
є інформаційною організацією. Інформацію, що опосередковує процес, та поведінку цієї інформації спочатку слід розуміти разом з так званими правилами бізнесу - перед тим, як розробляти або доповнювати рішення для цього процесу. Такий метод організації інформації кілька десятиліть тому називався нормалізацією даних.
Тоді можлива лише інженерія рішення, оскільки вирівнювання зернистості та модульності компонентів розчину з деталізацією та модульністю компонентів інформації є оптимальною стратегією.
Існують дві чи три суттєві перешкоди для організації інформації.
Відсутність сприйняття необхідності "нормалізації" моделі даних.
Висловлювання EF Codd щодо нормалізації даних є хибними, несправними та неоднозначними.
Останнє примха, що маскується як спритна інженерія - це хибне уявлення про те, що не слід планувати і обумовлювати організацію модулів вперед, тому що ви можете рефакторировать по мірі свого руху. Рефакторинг і постійні зміни, не перешкоджаючи майбутнім відкриттям, використовуються як привід. Тоді істотними виявленнями поведінки інформаційних процесів є використання методів обліку для затримки прибутку та атестації, тому важливі знання та їх обробка зараз вважаються не потрібними.
Не вигадуйте правил і не видайте жодних фетва проти цього лише тому, що ви любите свої специфічні звички програмування хіт-і-запуску.
Не забороняйте право власності на зброю з тієї причини, що є люди, які або не знають, як поводитися зі зброєю, або схильні до зловживань зі зброєю.
Якщо правила, з якими ви розмовляєте, призначені для початківців програмування, які не можуть професійно кодувати, і ви зараховуєте себе до них, тоді скажіть так - не оголошуйте свою фетву як застосовну до нормально нормалізованих моделей даних.
Мені байдуже, які початкові наміри батьків-засновників мали конституцію США. Мене не хвилюють неписані некодифіковані наміри. Мене хвилює лише те, що буквально кодифіковане в письмовій Конституції, і як я можу їх використати для ефективного функціонування суспільства.
Мене цікавить лише те, що мені дозволяють специфіки мови / платформи Java, і я маю намір використати їх у повному обсязі, щоб дати мені носій для того, щоб ефективно і ефективно висловлювати свої програмні рішення. Куртки не потрібні.
Потрібно записати додатковий код для зіставлення параметра для значення. Той факт, що засновники Java не передбачили відображення значень параметрів без написання вами того, що код відображення демонструє константи Enum, так само нецільове використання мови Java.
Тим більше, що вам не рекомендується нормалізувати і складати свої параметри, складеться помилкове враження, що параметри, змішані в сумку Enum, належать до одного і того ж виміру.
Не забувайте цього. Якщо ви розробили та нормалізували свою модель даних, і вони включають константи, то ці константи є контрактами. Якщо ви не нормалізували свою модель даних, то вам слід відповідати факту, який дається про те, як застосовувати обмежувальне кодування, щоб впоратися з цією шкідливою звичкою.
Тому інтерфейси є ідеальним способом реалізації договору Константи.
Так. Будь-хто міг ненавмисно реалізувати будь-який інтерфейс. Ніщо не стане на шляху таких ненавмисних програмістів.
Не розміщуйте обмежувальні укази для захисту імовірних недобрих практик, які спричиняють витік непідконтрольних / бродячих параметрів в API. Вирішіть фундаментальне питання, а не покладайте провину на константи інтерфейсу.
Нормального функціонуючого та ЕФЕКТИВНОГО програміста немає для того, щоб довести, як довго вона може перебувати під водою, наскільки далеко вона могла б ходити у бліскучій спеці чи мокрих грозах. Їй потрібно використовувати такий ефективний інструмент, як автомобіль, автобус або хоча б велосипед, щоб їздити на роботу 10 км щодня.
Не накладайте обмежень на інших програмістів лише тому, що у вас є езотерична аскетичність, одержима програмою без IDE.
OSGI - це така структура. Так само і указ проти констант інтерфейсу.
Константи інтерфейсу є ефективним та ефективним способом розміщення в контракті добре розроблених та нормалізованих компонентів моделі даних.
Константи інтерфейсу у відповідному приватному інтерфейсі, вкладені у файл класу, також є хорошою практикою для групування всіх ваших приватних констант, а не розкидання їх по всьому файлу.
Зараз я натрапив на це старе запитання кілька разів, і прийнята відповідь все ще мене бентежить. Після багато роздумів, я думаю, що це питання можна ще уточнити.
Просто порівняйте їх:
public final class Constants {
private Constants() {
// restrict instantiation
}
public static final double PI = 3.14159;
public static final double PLANCK_CONSTANT = 6.62606896e-34;
}
проти
public interface Constants {
double PI = 3.14159;
double PLANCK_CONSTANT = 6.62606896e-34;
}
Те саме використання. Набагато менше коду.
Я думаю, що відповідь @Pascal Thivent має неправильний наголос, ось моя версія його:
Вміщення статичних членів в інтерфейс ( і реалізація цього інтерфейсу ) є поганою практикою.
Цитата «Ефективна Java» має припущення про постійний інтерфейс, який реалізують інші, що, на мою думку, не повинно (і не відбудеться).
Коли ви створюєте постійний інтерфейс, який називається щось подібне Constants
, його ніхто не повинен реалізовувати. (хоча технічно це можливо, це єдине питання тут)
Стандартна бібліотека не може дозволити собі можливе неправильне використання дизайну, тому ви просто не побачите жодного.
Тим НЕ менше , для щоденних проектів нормальних розробників, що використовують інтерфейс констант набагато простіше , тому що вам не потрібно турбуватися про static
, final
, empty constructor
і т.д., і це не викличе якихось - або поганий питання дизайну. Єдиний недолік, про який я можу подумати, - це те, що він все ще має назву "інтерфейс", але не більше того.
Зрештою, я думаю, що всі лише цитують книги і дають думки та обґрунтування на свої позиції. Не виняток для мене. Можливо, рішення все ж залежить від розробників кожного проекту. Просто продовжуйте використовувати його, якщо ви відчуваєте себе комфортно. Найкраще, що ми можемо зробити, це зробити його послідовним протягом усього проекту .
public
також може бути опущений, оскільки це інтерфейс, що робить його просто double PI = 3.14159;
Використання Constants.PI
не потребує класу, використовуючи це для реалізації Constants
інтерфейсу! Я думаю, що інтерфейсний підхід набагато чистіший з точки зору використання, IMHO
Джошуа Блох, "Ефективна Java - Посібник з мов програмування":
Постійна схема інтерфейсу - це погане використання інтерфейсів. Те, що клас використовує деякі константи внутрішньо, є деталлю реалізації. Реалізація постійного інтерфейсу змушує цю деталь реалізації просочитися до експортованого API класу. Для користувачів класу не має жодних наслідків, що клас реалізує постійний інтерфейс. Насправді це може навіть збити з пантелику. Гірше, що це означає зобов'язання: якщо в майбутньому випуску клас буде змінено так, що йому більше не потрібно використовувати константи, він все одно повинен реалізувати інтерфейс для забезпечення бінарної сумісності. Якщо нефінальний клас реалізує постійний інтерфейс, усі його підкласи матимуть свої простори імен, забруднені константами в інтерфейсі.
Вони корисні, якщо у вас є загальні константи, які будуть використовуватися в класах, що реалізують інтерфейс.
Ось приклад: http://www.javapractices.com/topic/TopicAction.do?Id=32
Але зауважте, що рекомендована практика - використовувати статичний імпорт замість констант в інтерфейсах. Ось посилання: http://www.javapractices.com/topic/TopicAction.do?Id=195
Є відповіді, які є дуже резонансними.
Але у мене є деякі думки з цього питання. (може бути неправильним)
На мою думку, поля в інтерфейсі не повинні бути константами всього проекту, вони є лише засобом для інтерфейсу, а інтерфейси розширюють його та класи, які реалізують ці інтерфейси або мають тісний зв’язок з ними. Вони повинні використовуватися в певному діапазоні, не глобальному.
Два пункти щодо інтерфейсу:
Інтерфейс описує підмножину того, що може робити об’єкт, який реалізує його. (Це інтуїція)
Інтерфейс описує звичайні константи, за якими слідують об'єкти, які його реалізують.
Тому я думаю, що якщо константи не використовуються для глобальних констант , то це прийнятно:
implements
його (і, звичайно, використовувати ці загальні константи для реалізації).Приклад:
interface Drawable {
double GOLDEN_RATIO = 1.618033988;
double PI = 3.141592653;
...
// methods
...
}
public class Circle implements Drawable {
...
public double getCircumference() {
return 2 * PI * r;
}
}
void usage() {
Circle circle = new Circle(radius: 3.0);
double maxRadius = 5.0;
if ( circle.getCircumference() < 2 * Circle.PI * maxRadius ) {
...
}
}
У цьому прикладі:
Circle implements Drawable
ви відразу знаєте, що Circle
, ймовірно, відповідає константам, визначеним у Drawable
, інакше їм доведеться вибрати гірше ім’я, оскільки хороші PI
і GOLDEN_RATIO
вже прийняті!Drawable
об'єкти відповідають конкретному PI
та GOLDEN_RATIO
визначеному в Drawable
, можуть бути об'єкти, які не Drawable
мають різної точності співвідношення пі та золота.javax.swing.SwingConstants
Інтерфейс є прикладом , який отримав статичні поля , які використовуються серед тих, хто вагається класів. Це дозволяє легко використовувати щось подібне
this.add(LINE_START, swingcomponent);
this.add(this.LINE_START, swingcomponent);
або this.add(SwingComponents.LINE_START, swingcomponent);
Однак у цього інтерфейсу немає методів ...
Я наштовхнувся на це питання і подумав, що додам щось, про що не згадувалося. Загалом, я згоден з відповіддю Паскаля тут . Однак я не думаю, що константи інтерфейсу "завжди" є антипатерн.
Наприклад, якщо константи, які ви визначаєте, є частиною договору для цього інтерфейсу, я думаю, що інтерфейс є чудовим місцем для констант. У деяких випадках приватне підтвердження ваших параметрів не доцільно, не піддаючи контракту користувачам вашої реалізації. Без публічного контракту користувачі можуть лише здогадуватися, з чим у вас валідація, за винятком декомпіляції класу та читання вашого коду.
Отже, якщо ви реалізуєте інтерфейс, а в інтерфейсі є константи, які ви використовуєте для забезпечення своїх контрактів (наприклад, цілочисельні діапазони), то користувач вашого класу може бути впевнений, що він правильно використовує екземпляр інтерфейсу, перевіряючи проти констант в інтерфейсі. себе. Це було б неможливо, якби константи були приватними до вашої реалізації або ваша реалізація була приватною, або щось подібне.
Я використовую константи інтерфейсу при роботі з спільними константами між класами.
public interface TestConstants
{
String RootLevelConstant1 = "RootLevelConstant1";
interface SubGroup1
{
String SubGroupConstant1 = "SubGroup1Constant1";
String SubGroupConstant2 = "SubGroup1Constant2";
}
interface SubGroup2
{
String SubGroupConstant1 = "SubGroup2Constant1";
String SubGroupConstant2 = "SubGroup2Constant2";
}
}
Групування - це величезне надбання, особливо з великим набором констант.
Щоб використовувати їх, ви просто зв'язати їх між собою:
System.out.println(TestConstants.SubGroup1.SubGroupConstant1);
System.out.println(TestConstants.SubGroup2.SubGroupConstant1);
System.out.println(TestConstants.RootLevelConstant1);
поля повинні бути оголошені в інтерфейсі, щоб їх було легше ділитися і на них можна посилатись, не вводячи додаткового з’єднання.
Джерело: Стиль кодування Java Developer Tools