Я смотрю на некоторые проекты Java с открытым исходным кодом, чтобы проникнуть в Java, и заметил, что многие из них имеют какой-то интерфейс «констант».
Например, у processing.org есть интерфейс под названием PConstants.java , и большинство других базовых классов реализуют этот интерфейс. Интерфейс пронизан статическими элементами. Есть ли причина для такого подхода или это считается плохой практикой? Почему бы не использовать перечисления там, где это имеет смысл , или статический класс?
Мне кажется странным использовать интерфейс, позволяющий использовать какие-то псевдо «глобальные переменные».
public interface PConstants {
// LOTS OF static fields...
static public final int SHINE = 31;
// emissive (by default kept black)
static public final int ER = 32;
static public final int EG = 33;
static public final int EB = 34;
// has this vertex been lit yet
static public final int BEEN_LIT = 35;
static public final int VERTEX_FIELD_COUNT = 36;
// renderers known to processing.core
static final String P2D = "processing.core.PGraphics2D";
static final String P3D = "processing.core.PGraphics3D";
static final String JAVA2D = "processing.core.PGraphicsJava2D";
static final String OPENGL = "processing.opengl.PGraphicsOpenGL";
static final String PDF = "processing.pdf.PGraphicsPDF";
static final String DXF = "processing.dxf.RawDXF";
// platform IDs for PApplet.platform
static final int OTHER = 0;
static final int WINDOWS = 1;
static final int MACOSX = 2;
static final int LINUX = 3;
static final String[] platformNames = {
"other", "windows", "macosx", "linux"
};
// and on and on
}
static final
необязательно, это избыточно для интерфейса.platformNames
может бытьpublic
,static
иfinal
, но это, безусловно , не является постоянной. Единственный постоянный массив - это массив нулевой длины.static final
не обязательно является избыточным. Поле класса или интерфейса, содержащее толькоfinal
ключевое слово, будет создавать отдельные экземпляры этого поля по мере создания вами объектов класса или интерфейса. Использованиеstatic final
заставит каждый объект совместно использовать область памяти для этого поля. Другими словами, если у класса MyClass есть полеfinal String str = "Hello";
, для N экземпляров MyClass в памяти будет N экземпляров поля str. Добавлениеstatic
ключевого слова приведет только к 1 экземпляру.Ответы:
Обычно это считается плохой практикой. Проблема в том, что константы являются частью общедоступного «интерфейса» (точнее сказать) реализующего класса. Это означает, что реализующий класс публикует все эти значения во внешние классы, даже если они требуются только внутри. Константы распространяются по всему коду. Примером может служить интерфейс SwingConstants в Swing, который реализован десятками классов, которые «реэкспортируют» все свои константы (даже те, которые они не используют) как свои собственные.
Но не верьте мне на слово, Джош Блох также говорит, что это плохо:
Перечисление может быть лучшим подходом. Или вы можете просто поместить константы как общедоступные статические поля в классе, который не может быть создан. Это позволяет другому классу получать к ним доступ, не загрязняя свой собственный API.
источник
Вместо реализации «интерфейса констант» в Java 1.5+ вы можете использовать статический импорт для импорта констант / статических методов из другого класса / интерфейса:
Это позволяет избежать уродства, когда ваши классы реализуют интерфейсы, которые не имеют функциональности.
Что касается практики наличия класса только для хранения констант, я думаю, что иногда это необходимо. Есть определенные константы, которым просто нет естественного места в классе, поэтому лучше иметь их в «нейтральном» месте.
Но вместо использования интерфейса используйте последний класс с частным конструктором. (Делает невозможным создание экземпляра или подкласс класса, отправляя сильное сообщение о том, что он не содержит нестатических функций / данных.)
Например:
источник
Я не претендую на право быть правым, но давайте посмотрим на этот небольшой пример:
ToyotaCar ничего не знает о FordCar, а FordCar не знает о ToyotaCar. Принцип CarConstants надо менять, но ...
Константы не следует менять, потому что колесо круглое, а egine - механическое, но ... В будущем инженеры-исследователи Toyota изобрели электронный двигатель и плоские колеса! Давайте посмотрим на наш новый интерфейс
и теперь мы можем изменить нашу абстракцию:
в
И теперь, если нам когда-нибудь понадобится изменить основное значение, если ДВИГАТЕЛЬ или КОЛЕСО, мы можем изменить интерфейс ToyotaCar на уровне абстракции, не касаясь реализаций.
Я знаю, это НЕ БЕЗОПАСНО, но я все еще хочу знать, что вы думаете об этом
источник
В Java есть много ненависти к этому шаблону. Однако интерфейс статических констант иногда имеет значение. Вам необходимо в основном выполнить следующие условия:
Концепции являются частью открытого интерфейса нескольких классов.
Их ценности могут измениться в будущих выпусках.
Например, предположим, что вы пишете расширение для гипотетического языка запросов. В этом расширении вы собираетесь расширить синтаксис языка некоторыми новыми операциями, которые поддерживаются индексом. Например, у вас будет R-Tree, поддерживающее геопространственные запросы.
Итак, вы пишете публичный интерфейс со статической константой:
Позже новый разработчик думает, что ему нужно создать лучший индекс, поэтому он приходит и создает реализацию R *. Реализуя этот интерфейс в своем новом дереве, он гарантирует, что разные индексы будут иметь идентичный синтаксис на языке запросов. Более того, если позже вы решите, что имя «nearTo» сбивает с толку, вы можете изменить его на «insideDistanceInKm» и знать, что новый синтаксис будет соблюдаться всеми реализациями вашего индекса.
PS: Вдохновение для этого примера взято из пространственного кода Neo4j.
источник
Учитывая преимущество ретроспективного взгляда, мы видим, что Java во многих отношениях не работает. Одним из основных недостатков Java является ограничение интерфейсов абстрактными методами и статическими конечными полями. Новые, более сложные объектно-ориентированные языки, такие как Scala, подразделяют интерфейсы на черты, которые могут (и обычно включают) конкретные методы, которые могут иметь нулевую арность (константы!). Для ознакомления с описанием черт как единиц составного поведения см. Http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf . Краткое описание того, как черты в Scala сравниваются с интерфейсами в Java, см. Http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-5, В контексте обучения объектно-ориентированному проектированию упрощенные правила, такие как утверждение, что интерфейсы никогда не должны включать статические поля, являются глупыми. Многие черты естественно включают константы, и эти константы соответственно являются частью общедоступного «интерфейса», поддерживаемого чертой. При написании кода Java не существует чистого, элегантного способа представления признаков, но использование статических полей final в интерфейсах часто является частью хорошего обходного пути.
источник
Согласно спецификации JVM, поля и методы в интерфейсе могут иметь только Public, Static, Final и Abstract. Ссылка из Inside Java VM
По умолчанию все методы в интерфейсе абстрактны, даже если вы не упомянули об этом явно.
Интерфейсы предназначены только для описания. Он не может содержать никаких реализаций. Поэтому, чтобы избежать реализации классов для изменения спецификации, она делается окончательной. Поскольку интерфейс не может быть создан, они становятся статическими для доступа к полю с использованием имени интерфейса.
источник
У меня недостаточно репутации, чтобы дать комментарий Плеероку, поэтому я должен создать ответ. Я сожалею об этом, но он приложил немало усилий, и я хотел бы ему ответить.
Плеерок, вы создали идеальный пример, чтобы показать, почему эти константы должны быть независимыми от интерфейсов и от наследования. Для клиента приложения не важно, есть ли техническая разница между этими реализациями автомобилей. Для клиента они такие же, просто автомобили. Итак, клиент хочет взглянуть на них с этой точки зрения, которая представляет собой интерфейс, подобный I_Somecar. На протяжении всего приложения клиент будет использовать только одну точку зрения, а не разные для каждой марки автомобиля.
Если клиент хочет сравнить автомобили перед покупкой, у него может быть такой метод:
Интерфейс - это договор о поведении, который показывает разные объекты с одной точки зрения. То, как вы его спроектируете, у каждой марки автомобилей будет своя наследственная линия. Хотя на самом деле это совершенно правильно, потому что автомобили могут быть настолько разными, что это может быть похоже на сравнение совершенно разных типов объектов, в конце концов, есть выбор между разными автомобилями. И это перспектива интерфейса, которым должны поделиться все бренды. Выбор констант не должен делать это невозможным. Пожалуйста, обратите внимание на ответ Зарконнена.
источник
Это появилось еще до того, как появилась Java 1.5 и она не принесла нам перечислений. До этого не было хорошего способа определить набор констант или ограниченных значений.
Это все еще используется, большую часть времени либо для обратной совместимости, либо из-за количества рефакторинга, необходимого для избавления от многих проектов.
источник