Является ли интерфейс как ярлыки плохой практикой в ​​Java OO? - PullRequest
8 голосов
/ 17 сентября 2009

Во время синтаксического анализа некоторых XML-файлов я сталкиваюсь с ситуацией, когда мне необходимо использовать интерфейс в качестве меток для определения того, что определенные теги принадлежат определенной категории, например, я создал интерфейс Tag для идентификации что эти классы используются для представления тегов xml, а ContainableTag указывает, что определенные теги могут быть одним из дочерних тегов некоторых тегов.

Затем я наткнулся на эту страницу: http://xahlee.org/java-a-day/interface.html (Пожалуйста, найдите сеанс " Интерфейс как метки ".). Это говорит:

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

Значит, интерфейс как ярлыки обязательно плохая практика? Как программист Java, у нас есть другие альтернативы?

Ответы [ 3 ]

8 голосов
/ 17 сентября 2009

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

7 голосов
/ 17 сентября 2009

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

Что касается упомянутой вами статьи, я не вижу смысла утверждать, что если класс синтаксически / структурно «выполняет» интерфейс, этот интерфейс может / должен применяться автоматически к классу («Любой класс может объявить его [ RandomAccess] в качестве интерфейса ... "). Это обратное мышление, на мой взгляд.

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

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

5 голосов
/ 17 сентября 2009

Аннотации не обязательно то, что вы хотите. Интерфейсы тегов - это способ вписать свойство типа в сам тип. Например, если вы собираетесь начать писать код, похожий на этот:

@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).

Редактировать: У меня немаловажная поддержка здесь.

...