Какая польза от констант интерфейса? - PullRequest
107 голосов
/ 17 апреля 2010

Я изучаю Java и только что обнаружил, что Интерфейс может иметь поля, которые являются статическими и окончательными. До сих пор я не видел таких примеров. Каковы некоторые из вариантов использования этих констант интерфейса, и можно ли их увидеть в стандартной библиотеке Java?

Ответы [ 11 ]

166 голосов
/ 17 апреля 2010

Помещение статических элементов в интерфейс (и реализация этого интерфейса) является плохой практикой , и даже для него есть название, Constant Interface Antipattern , см. Действует Ява , позиция 17:

Шаблон постоянного интерфейса плохо использует интерфейсы . То, что класс использует некоторые константы внутри, является деталью реализации. Реализация постоянного интерфейса вызывает утечку этой детали реализации в экспортируемый API класса. Для пользователей класса не имеет значения, что класс реализует постоянный интерфейс. На самом деле, это может даже запутать их. Хуже того, он представляет собой обязательство: если в будущем выпуске класс будет изменен так, что ему больше не нужно будет использовать константы, он все равно должен реализовать интерфейс для обеспечения двоичной совместимости. Если нефинальный класс реализует постоянный интерфейс, все его подклассы будут иметь свои пространства имен, загрязненные константами в интерфейсе.

В библиотеках платформы Java есть несколько постоянных интерфейсов, таких как java.io.ObjectStreamConstants. Эти интерфейсы следует рассматривать как аномалии и не следует подражать.

Чтобы избежать некоторых подводных камней постоянного интерфейса (поскольку вы не можете помешать людям реализовать его), следует отдавать предпочтение подходящему классу с закрытым конструктором (пример заимствован из Wikipedia ):

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);
    }
}
8 голосов
/ 22 января 2018

" Шаблон постоянного интерфейса плохо использует интерфейсы "

Кто бы ни придумал эту гипотезу, какой бы гуру он ни был, он придумал ее на основе необходимости продолжать эффективно внедрять вредные привычки и практики. Гипотеза основана на продвижении обоснованности вредных привычек проектирования программного обеспечения.

Я написал ответное опровержение этой гипотезы здесь: Каков наилучший способ реализации констант в Java? , объясняющий необоснованность этой гипотезы.

В течение 10 лет этот вопрос оставался открытым, пока он не был закрыт в течение 2 часов после того, как я опубликовал свои доводы, оправдывающие эту гипотезу, тем самым разоблачая нежелание обсуждать тех, кто придерживается этой ошибочной гипотезы.

Это то, что я высказал против гипотезы

  • Основой для сохранения этой гипотезы является необходимость в методах и ОГРАНИЧИТЕЛЬНЫХ правилах, чтобы справиться с последствиями вредных программных привычек и методологий.

  • Сторонники настроения " Шаблон интерфейса с постоянным интерфейсом - плохое использование интерфейсов" не в состоянии представить какие-либо причины, кроме причин, вызванных необходимостью справиться с последствиями этих плохих привычки и практики.

  • Решить фундаментальную проблему.

  • И тогда почему бы не использовать в полной мере и не использовать все языковые возможности структуры языка Java для собственного удобства. Куртки не требуются. Зачем придумывать правила, чтобы забаррикадировать ваш неэффективный образ жизни, чтобы различать и обвинять в более эффективном образе жизни?

Основная проблема

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

Тогда возможна только разработка решения, поскольку оптимальной стратегией является выравнивание гранулярности и модульности компонентов решения с гранулярностью и модульностью компонентов информации.

Существует два или три существенных препятствия для организации информации.

  1. Отсутствие восприятия необходимости модели данных "нормализация".

  2. Заявления Э. Ф. Кодда о нормализации данных ошибочны, ошибочны и неоднозначны.

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

Хорошей практикой является использование интерфейсных констант.

Не придумывайте правил и не выдвигайте против них фетву только потому, что вам нравятся ваши привычные хитроумные привычки.

Не запрещайте владение оружием по той причине, что есть люди, которые либо не знают, как обращаться с оружием, либо склонны злоупотреблять оружием.

Если придуманные вами правила предназначены для программирования новичков, не умеющих профессионально программировать, и что вы считаете себя среди них, то скажите так - не объявляйте вашу фетву применимой к правильно нормализованным моделям данных.

Глупая аргументация - не предполагалось, что камбалы языка Java будут использовать интерфейсы таким образом? Мне все равно, какие первоначальные намерения отцы-основатели имели для Конституции США. Меня не волнуют неписаные некодифицированные намерения. Меня волнует только то, что буквально кодифицировано в письменной Конституции, и как я могу использовать их для эффективного функционирования общества. Меня интересует только то, что позволяют мне спецификации языка / платформы Java, и я намерен использовать их в полной мере, чтобы предоставить мне возможность эффективно и действенно выражать свои программные решения. Куртки не требуются. Использование констант Enum на самом деле ужасная практика.

Требуется написать дополнительный код для сопоставления параметра со значением. Тот факт, что основатели Java не предусмотрели сопоставление значения параметра без того, что вы написали, что код сопоставления демонстрирует, что константы Enum являются непреднамеренным использованием языка Java.

Тем более что вам не рекомендуется нормализовать и компоновать ваши параметры, может возникнуть ложное впечатление, что параметры, смешанные в пакет Enum, принадлежат одному и тому же измерению.

Константы являются контрактом API

Не забывайте это. Если вы разработали и нормализовали свою модель данных, и они содержат константы, то эти константы являются контрактами. Если вы не нормализовали свою модель данных, вам следует придерживаться фатв, приведенных в том, как применять ограничительное кодирование, чтобы справиться с этой вредной привычкой.

Таким образом, интерфейсы являются идеальным способом реализации контракта Константы.

Странное предположение - что, если интерфейс непреднамеренно будет реализован.

Да. Любой может непреднамеренно реализовать любой интерфейс. Ничто не помешает таким непреднамеренным программистам.

Дизайн и нормализация вашей модели данных от утечек

Не размещайте ограничительные указы для защиты от предполагаемых недобросовестных действий, приводящих к утечке несокращенных / случайных параметров в API. Решите фундаментальную проблему, а не возлагайте вину на константы интерфейса.

Не использовать IDE - плохая практика

Нормально работающий и ЭФФЕКТИВНЫЙ программист не может доказать, как долго она может оставаться под водой, как далеко она может ходить при жаре или влажных грозах. Она должна использовать эффективный инструмент, такой как автомобиль или автобус или, по крайней мере, велосипед, чтобы ежедневно проехать 10 миль до работы.

Не устанавливайте ограничения на коллег-программистов только потому, что у вас есть эзотерическая аскетическая одержимость программированием без IDE.

Пара фреймворков разработана, чтобы помочь программистам продолжать эффективно практиковать вредные привычки.

OSGI - это такая структура. Так же как и указ против констант интерфейса.

Поэтому окончательный ответ ...

Константы интерфейса - это эффективный и действенный способ включения в контракт хорошо спроектированных и нормализованных компонентов модели данных.

Интерфейсные константы в закрытом интерфейсе с соответствующим именем, вложенным в файл класса, также являются хорошей практикой для группировки всех ваших личных констант, а не для разбрасывания их по всему файлу.

7 голосов
/ 17 апреля 2010

Джошуа Блох, «Эффективная Java - Руководство по языку программирования»:

Шаблон постоянного интерфейса плохо использует интерфейсы. Это класс использует некоторые константы внутри, это деталь реализации. Реализация постоянного интерфейса приводит к тому, что эта деталь реализации утечка в экспортированный API класса. Это не имеет никакого значения для пользователи класса, что класс реализует постоянный интерфейс. В На самом деле, это может даже запутать их. Хуже того, это представляет собой обязательство: если в будущем выпуске класс будет изменен так, чтобы он больше не нуждался чтобы использовать константы, он все равно должен реализовать интерфейс для обеспечения двоичная совместимость Если нефинальный класс реализует константу интерфейс, все его подклассы будут загрязнены их пространства имен константами в интерфейсе.

3 голосов
/ 17 апреля 2010

Они полезны, если у вас есть общие константы, которые будут использоваться в классах, реализующих интерфейс.

Вот пример: http://www.javapractices.com/topic/TopicAction.do?Id=32

Но учтите, что рекомендуется использовать статический импорт вместо констант в интерфейсах. Вот ссылка: http://www.javapractices.com/topic/TopicAction.do?Id=195

2 голосов
/ 10 августа 2018

Я сталкивался с этим старым вопросом несколько раз, и принятый ответ все еще смущает меня. После долгих раздумий я думаю, что этот вопрос можно уточнить.

Зачем использовать интерфейс Constant?

Просто сравните их:

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 {

    public double PI = 3.14159;
    public double PLANCK_CONSTANT = 6.62606896e-34;
}

То же использование. Гораздо меньше кода.

Плохая практика?

Я думаю, что ответ @Pascal Thivent имеет неправильный акцент, вот моя версия этого:

Вставка статических элементов в интерфейс ( и реализация этого интерфейса ) - плохая практика.

Цитата из Effective Java предполагает, что другие интерфейсы реализуют постоянный интерфейс, что, я думаю, не должно (и не будет) происходить.

Когда вы создаете постоянный интерфейс с именем что-то вроде Constants, он не должен реализовываться никем. (хотя технически это возможно, что является единственной проблемой здесь)

В стандартной библиотеке этого не произойдет

Стандартная библиотека не может допустить возможного неправильного использования дизайна, поэтому вы просто не увидите там ничего.

Однако , для повседневных проектов обычных разработчиков, использование интерфейса констант намного проще, потому что вам не нужно беспокоиться о static, final, empty constructor и т. Д., И это будет НЕ вызывает проблем с дизайном. Единственный недостаток, который я могу вспомнить, это то, что он по-прежнему имеет название «интерфейс», но не более того.

Бесконечные дебаты

В конце я думаю, что все просто цитируют книги и высказывают мнения и оправдания своим позициям. Для меня не исключение. Возможно, решение остается за разработчиками каждого проекта. Просто используйте его, если вам удобно. Лучшее, что мы можем сделать, - это сделать его согласованным на протяжении всего проекта .

2 голосов
/ 27 апреля 2018

Есть ответы, которые очень резонно.

Но у меня есть некоторые мысли по этому вопросу. (может быть не так)

По моему мнению, поля в интерфейсе не должны быть константами для всего проекта, они являются только средством интерфейса, и интерфейсы расширяют его и классы, которые реализуют эти интерфейсы или имеют с ними тесную связь. Они должны использоваться в определенном диапазоне, не глобальном.

1 голос

Две точки об интерфейсе:

  • Интерфейс описывает подмножество того, что может объект , который реализует его. (Это интуиция)

  • Интерфейс описывает общие константы , за которыми следуют объекты , которые его реализуют.

    • Эти общие константы предназначены для , чтобы клиент знал больше об этих объектах.
    • Итак, Интерфейс констант действительно нелогичен для определения глобальных констант , поскольку интерфейс используется для описания некоторых объектов , а не всех объектов / нет объекта (рассмотрим значение global ).

Поэтому я думаю, что если Интерфейс констант не используется для глобальных констант , то это приемлемо:

  • Если эти общие константы имеют хорошие имена, они рекомендуют разработчику использовать их (см. Мой первый пункт для примера ниже)
  • Если класс хочет синхронизироваться с этими классами в соответствии со спецификацией, просто 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 с разной точностью пи и золотого сечения.
1 голос
/ 03 января 2017

Я сталкивался с этим вопросом и думал, что добавлю что-то, что не было упомянуто. В общем, я согласен с ответом Паскаля здесь . Тем не менее, я не думаю, что константы интерфейса "всегда" являются антипаттернами.

Например, если определяемые вами константы являются частью контракта для этот интерфейс, я думаю, интерфейс является отличным местом для констант. В некоторых случаях просто не подходит для частной проверки ваших параметров без раскрытия контракта пользователям вашей реализации. Без открытого контракта пользователи могут только догадываться, с чем вы проверяете, если не считать декомпиляцию класса и чтение вашего кода.

Таким образом, если вы реализуете интерфейс, и у интерфейса есть константы, которые вы используете для обеспечения ваших контрактов (например, целочисленные диапазоны), то пользователь вашего класса может быть уверен, что он правильно использует экземпляр интерфейса, сверяясь с константами в интерфейсе сами. Это было бы невозможно, если бы константы были приватными для вашей реализации или вашей реализации был пакет частный или что-то.

1 голос
/ 17 апреля 2010

Интерфейс javax.swing.SwingConstants является примером, который получил статические поля, которые используются среди классов свинга. Это позволяет вам легко использовать что-то вроде

  • this.add(LINE_START, swingcomponent);
  • this.add(this.LINE_START, swingcomponent); или
  • this.add(SwingComponents.LINE_START, swingcomponent);

Однако этот интерфейс не имеет методов ...

0 голосов
/ 12 декабря 2013

поля должны быть объявлены в интерфейсе, чтобы их было легче поделиться и можно ссылаться без введения дополнительной связи.

Источник: Стиль разработки инструментов Java для разработчиков

...