Является ли интерфейс как ярлыки плохой практикой в Java OO?
Вопрос
Во время синтаксического анализа некоторых XML-файлов я сталкиваюсь с ситуацией, когда мне приходится использовать интерфейс в качестве меток для определения того, что определенные теги принадлежат определенной категории, например, я создал интерфейс Tag для определить, что эти классы используются для представления тегов xml, а ContainableTag указать, что определенные теги могут быть одним из дочерних тегов некоторых тегов.
Затем я наткнулся на эту страницу: http://xahlee.org/java-a -day / interface.html (см. сеанс " Интерфейс как метки "). Это говорит:
Суть проблемы в том, что это кусок математической неуместности в язык. Как механизм маркировки на языке, для возможного извлечь выгоду из разработки программного обеспечения в перспективе тогда не должно быть разработан как часть класса Интерфейс, так как концепция маркировка и концепция программирования интерфейс, семантически несопоставимы.
Так что интерфейс как ярлыки обязательно плохая практика? Как программист Java, у нас есть другие альтернативы?
Решение
Интерфейсы как маркеры были в значительной степени заменены механизмом аннотации в Java 5 или более поздней версии. Они позволяют добавлять произвольные метаданные. Если ваши интерфейсы пусты и служат только в качестве маркеров классов, вам следует вместо этого использовать аннотации.
Другие советы
Несмотря на то, что аннотации могут предоставлять альтернативу для того, что выполняют интерфейсы маркеров, они доступны только в Java и плохо интегрируются с IDE: я также использую интерфейсы маркеров для маркировки связанных концепций в своем проекте, и затем я могу использовать тип браузер иерархии, чтобы найти всех участников (я думаю, это в конечном итоге будет поддерживаться основными IDE для аннотаций в ближайшее время).
Что касается упомянутой вами статьи, я не вижу смысла в том, чтобы утверждать, что если класс синтаксически / структурно "выполняет" интерфейс, этот интерфейс может / должен применяться автоматически к классу («Любой класс может объявить его [RandomAccess] как интерфейс ...»). Это обратное мышление, по моему мнению.
Я бы сказал, что места, где такой интерфейс маркера используется в операторе instanceof, используют инвертированную логику, но пока вы застряли в языке без множественного наследования, аспектов и аннотаций, я не вижу лучшего способ сделать это, не выходя из базового языка.
Также обратите внимание, что этот тупиковый аргумент о том, что пустой интерфейс всегда применим, также может применяться к аннотациям.
Аннотации не обязательно то, что вы хотите. Интерфейсы тегов - это способ вписать свойство типа в сам тип. Например, если вы собираетесь начать писать код, похожий на этот:
@interface ContainableTag{}
@ContainableTag public class Foo {}
// ... elsewhere...
/**
* Adds obj as a child element.
* @throws IllegalArgumentException if obj is not tagged with
* the ContainableTag annotation.
*/
public void addElement(Object obj){
if (!obj.getClass().isAnnotationPresent(ContainableTag.class))
throw new IllegalArgumentException("obj is not a ContainableTag");
// add the containable tag as an element
}
Тогда подумайте, действительно ли вы думаете, что это выглядит лучше:
interface ContainableTag {}
public class Foo implements ContainableTag {}
// ... elsewhere...
public void addElement(ContainableTag ct){
// add the containable tag as an element
}
Конечно, интерфейс тегов не предоставляет никакой информации о том, какое поведение обеспечивает сам тип, но он делает , чтобы другие типы могли применять это свойство без поведения. Я, конечно, был бы избавлен от множества досадных ошибок, если бы ObjectOutputStream
имел метод writeObject (Serializable)
, а не writeObject (Object)
. р>
Изменить. У меня есть немаловажная поддержка здесь.