Есть ли в Java идиома пустых методов, которые существуют для удовлетворения интерфейса?

Допустим, у меня есть класс Foo реализация интерфейса, такого как MouseListener, MouseListener интерфейс состоит из пяти методов, но я хочу переопределить только один из них (mouseClicked()). Есть ли стандартный, идиоматический способ форматирования других методов?

Я хотел написать следующее:

@Override
public void mouseClicked(MouseEvent e) {
    // (...) <-- actual code here
}

@Override
public void mouseEntered(MouseEvent e) {
    // Do nothing.  Exists to satisfy MouseListener interface.
}

@Override
public void mouseExited(MouseEvent e) {
    // Do nothing.  Exists to satisfy MouseListener interface.
}

@Override
public void mousePressed(MouseEvent e) {
    // Do nothing.  Exists to satisfy MouseListener interface.
}

@Override
public void mouseReleased(MouseEvent e) {
    // Do nothing.  Exists to satisfy MouseListener interface.
}

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

public void mouseClicked(MouseEvent e) {
    // (...) <-- actual code here
}

public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}

Я в целом согласен с этим, и я понимаю намерения автора, но это становится ужасно, когда ( рекомендуется) @Override аннотации добавляются.

Я не особенно опытный Java-кодер, поэтому я решил спросить, существует ли соглашение. Мысли?

10 ответов

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

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

@Override
void foo() {
  // No implementation necessary
}

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

В общем, то, о чем вы говорите, это расширение шаблона пустых объектов. Вы определяете Null Object и расширяете его, переопределяя только те методы, которые вам нужны.

В качестве примера способа автоматизации этого в моих аннотациях bean-компонентов JavaDude ( http://code.google.com/p/javadude/wiki/Annotations) вы можете сделать что-то вроде следующего. [ПРИМЕЧАНИЕ: я бы не рекомендовал делать это для MouseListener, поскольку MouseAdapter уже существует, и вы можете просто создать его подкласс... Следующее полезно для других больших интерфейсов, где вы хотите реализовать только несколько методов выбора]

@Bean(nullObjectImplementations = @NullObject(type=MouseListener.class))
public class MyMouseHandler extends MyMouseHandlerGen {
    public void mouseClicked(MouseEvent e) {
        // your handling of a MouseClick
    }
}

Затем вы можете использовать MyMouseHandler для обработки клика.=

Примечание: MouseAdapter был действительно плохим выбором для имени класса в JRE/JDK. Это не экземпляр шаблона GoF Adapter; это действительно реализация Null Object для MouseListener.

Кстати: вы можете поместить @Override в ту же строку, что и объявление метода - для вашего примера вы можете иметь

@Override public void mousePressed(MouseEvent e) { /* not needed */ }
// et al

Используйте MouseAdapter

Есть несколько способов сделать это. В Oracle java Convention p6.4 (стр. 11) сказано, что пустые методы должны выглядеть

public void empty() {}

Есть также документ Стива Йоханана, написанный в 2003 году, в котором говорится, что

public void empty()
{
}

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

MouseAdapter отлично подходит для этого конкретного случая, а идиома Adapter великолепна в целом. Адаптер имеет пустые реализации всех методов интерфейса, что позволяет вам создавать подклассы и реализовывать только те методы, которые относятся к вашему классу. Адаптер может альтернативно, как предлагает Эндрю Хэйр, генерировать исключение NotImplementedException.

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

Я нашел это во время поиска этого точного вопроса. Я использую прокрутки, где мне нужно на ScrollStateChanged, но не на Scroll. Я склонялся к:

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
            int totalItemCount) {
    return;         
} 

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

Изменить: это то, что я остановился на:

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
            int totalItemCount) {return;}

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

Я не думаю, что это особенно важно. Для моих личных вкусов я не люблю видеть закрывающую скобку рядом с открытием, которая дает:

public void mouseEntered(MouseEvent e) {
}

Немного пусто, но хорошо. В случае возвращаемого значения мы можем сделать его похожим, что вы не получите с [] стиль.

Но когда дело доходит до редкого случая в циклах, мне нравится точка с запятой там:

// Made up example.
while (++i < len && str.charAt(i) != '\0') {
    ;
}

Что бы дать:

public void mouseEntered(MouseEvent e) {
    ;
}

В случае catch пункты, вы должны иметь хорошее оправдание в комментарии (возможно, прерывание).

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

Вероятно, самое важное, что вы должны сделать, это понять, что вы намерены, чтобы метод не имел реализации. В конкретном случае MouseAdapterВы, вероятно, не хотите бросать UnsupportedOperationException, но в целом это, вероятно, хороший сигнал о том, что вы не собираетесь предоставлять реализацию. Обычно требуется комментарий в исходном коде (или, лучше, в документации метода), объясняющий, почему вы не полностью реализуете интерфейс.

Другие вопросы по тегам