Должен ли класс реализовывать интерфейс только для констант? - PullRequest
6 голосов
/ 14 января 2010

Сегодня я посмотрел на класс ZipEntry и обнаружил следующее:

public class ZipEntry implements ZipConstants, Cloneable

ZipConstants не определяет методы - только константы (static final int LOCHDR = 30)

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

public interface Constants {
    static final int CONST = 2;
}

public class implements Constants {
    int doSomething(int input) {
        return CONST * input;
    }
}

Есть ли другая причина не использовать это, кроме:

  • сначала запутывается, откуда исходит константа
  • считается неправильным использовать интерфейсы для определения констант

Мне любопытно, потому что это определенно не очень распространенная практика.

Ответы [ 6 ]

16 голосов
/ 14 января 2010

Другие причины не использовать это:

Начиная с Java 5, существует функция «чистого» языка, которая достигает той же цели: статический импорт .

Реализация интерфейсов для использования констант - это в основном хак до Java-5 для имитации статического импорта.

3 голосов
/ 14 января 2010

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

  1. Повторное использование кода
  2. подтип

По моему опыту, использование подклассов или реализация интерфейса просто для предотвращения дублирования кода приводит к проблемам. Ваш код становится более хрупким. Например, кто-то может случайно переопределить константу, особенно если ваша иерархия классов имеет несколько классов.

Часто лучше использовать композицию, чтобы сохранить код сухим.

Другая проблема с использованием наследования таким способом заключается в том, что обычно этот тип наследования является частью API вашего класса. Иерархия класса видна за пределами класса. Это нарушает инкапсуляцию. Вам не нужно показывать использование вами констант вне класса, они связаны с тем, как вы решили реализовать свой класс, и не являются частью его API (в вашем примере).

Это может привести к ужасным проблемам обратной совместимости. Кто-то может прийти и написать код, подобный этому:

public interface Constants {
   static final int CONST = 2;
}

public class MyClass implements Constants {
   int doSomething(int input) {
    return CONST * input;
   }
}

public class ThirdPartyClass {
   int doSomethingElse(int input) {
     return MyClass.CONST + input;
   }
}

Теперь, если вы решите, что вам больше не нужно использовать CONST в MyClass, вы застряли. Потому что ThirdPartyClass создает зависимость от CONST, доступного в MyClass.

Вы можете закончить с этим. Где MyClass не использует какие-либо константы в интерфейсе, но все еще должен реализовать это.

public interface Constants {
   static final int CONST = 2;
}

public class MyClass implements Constants {
   int doSomething(int input) {
    return input;
   }
}

public class ThirdPartyClass {
   int doSomethingElse(int input) {
     return MyClass.CONST + input;
   }
}

Короче говоря; никогда не делай этого!

3 голосов
/ 14 января 2010

Это не так уж редко, как вы думаете, например, при статическом анализе Parasofts JTest и правило, согласно которому константы должны быть объявлены в class, и правило, что константы должны быть объявлены в interface s присутствуют, и проект должен выбирать между ними.

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

2 голосов
/ 14 января 2010

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

Это плохая причина не делать что-то. На самом деле это вовсе не причина.

EDIT

Учтите это.

  • Причиной того, что XXX - это плохой стиль, является YYY.
  • Причина, по которой вы должны сделать XXX, в том, что это плохой стиль.

Сколько существенных причин не делать XXX? Один или два?

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

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

На самом деле, даже причина «это сбивает с толку» ФП указана не полностью. ПОЧЕМУ это сбивает с толку?

Поскольку интерфейс обычно является типом с классами, которые реализуют интерфейс, являются подтипом. Но интерфейс только с константой не является типом в каком-либо полезном смысле, и классы, которые реализуют интерфейс, не являются подтипами в любом полезном смысле. В конечном счете, это реальная причина того, что реализация интерфейсов только для констант называется плохим стилем и «анти-паттерном», и это главная причина, по которой статический импорт был добавлен в Java 5.

0 голосов
/ 14 января 2010

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

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

0 голосов
/ 14 января 2010

Нет, это также известно как «Постоянный интерфейс Antipattern». Альтернативой является написание конкретного класса, который определяет константы, а затем использует статический импорт.

Константы класса

package util;

public class Constants {
    public static final String CONSTANT_STRING = "abc";

    private Constants() {
        throw new AssertionError(); 
    }
}

Класс теста

import static util.Constants.CONSTANT_STRING;

public class Test {
    System.out.println(CONSTANT_STRING);
}

См

1012 * Википедия *

для получения более подробной информации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...