Причины не использовать не реализованные интерфейсы для хранения констант - PullRequest
5 голосов
/ 10 июня 2011

В своей книге Эффективная Java Джошуа Блох рекомендует не использовать интерфейсы для хранения констант,

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

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

Например,

public interface SomeInterface {
    public static final String FOO = "example";
}

public class SomeOtherClass {
    //notice that this class does not implement anything
    public void foo() {
        thisIsJustAnExample("Designed to be short", SomeInteface.FOO);
    }
}

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

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

Ответы [ 4 ]

5 голосов
/ 10 июня 2011

Полагаю, он справляется со своей задачей, но, как однажды сказал друг: «Вы можете попробовать вытереть пол осьминогом; он может выполнить работу, но это не тот инструмент».

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

Полагаю, я не понимаю, почему эти значения общедоступны, если они просто будут использоваться в классе в частном порядке.Почему бы просто не переместить их в класс?Теперь, если эти значения будут использоваться группой классов, то почему бы не создать enum?Другой шаблон, который я видел, - это класс, который просто содержит публичные константы.Это похоже на шаблон, который вы описали.Однако класс можно сделать окончательным, чтобы его нельзя было расширять;ничто не мешает разработчику реализовать ваш интерфейс.В этих ситуациях я просто склонен использовать enum.

ОБНОВЛЕНИЕ

Это был ответ на комментарий, но потом он стал длинным.Создание интерфейса для хранения только одного значения еще более расточительно!:) Для этого вы должны использовать частную константу.Хотя помещать несвязанные значения в одно перечисление плохо, вы можете сгруппировать их в отдельные перечисления или просто использовать частные константы для класса.

Кроме того, если кажется, что все эти классы совместно используют эти несвязанные константы (ночто имеет смысл в контексте класса), почему бы не создать абстрактный класс, в котором вы определяете эти константы как protected?Все, что вам нужно сделать, это расширить этот класс, и ваши производные классы будут иметь доступ к константам.

3 голосов
/ 10 июня 2011

Я не думаю, что класс с закрытым конструктором лучше, чем использование интерфейса.

В цитате говорится, что использование implements ConstantInterface не является лучшей практикой, поскольку этот интерфейс становится частью API.

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

2 голосов
/ 10 июня 2011

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

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

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

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

0 голосов
/ 10 июня 2011

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

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

  • Вы можете использовать enums для группировки связанных констант и даже добавления к ним методов
  • Вы можете использовать Связки ресурсов для текста пользовательского интерфейса
  • используйте Map<String,String>, пропущенный через Collections.unmodifiableMap для более общих нужд
  • вы также можете читать константы из файла, используя java.util.Properties, и переносить или разбивать его на подклассы для предотвращения изменений

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

...