Подтвердить что ты не робот

Являются ли интерфейсы допустимой заменой классов полезности в Java 8?

В течение последнего десятилетия или около того я использовал шаблон ниже для своих классов служебных программ Java. Класс содержит только статические методы и поля, объявляется final, поэтому он не может быть расширен и имеет конструктор private, поэтому он не может быть создан.

public final class SomeUtilityClass {
    public static final String SOME_CONSTANT = "Some constant";

    private SomeUtilityClass() {}

    public static Object someUtilityMethod(Object someParameter) {
        /* ... */

        return null;
    }
}

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

public interface SomeUtilityInterface {
    String SOME_CONSTANT = "Some constant";

    static Object someUtilityMethod(Object someParameter) {
        /* ... */

        return null;
    }
}

Это позволяет мне избавиться от конструктора и много ключевых слов (public, static, final), которые неявны в интерфейсах.

Есть ли недостатки в этом подходе? Есть ли какие-либо преимущества в использовании служебного класса над служебным интерфейсом?

4b9b3361

Ответ 1

Исходя из того, кто придумал шаблон Constant Interface анти-шаблон, я бы сказал, хотя вы не предполагаете, что клиент реализует интерфейс, все еще возможно, возможно, проще и shouldn:

API-интерфейсы

должны быть просты в использовании и трудно использовать. Легко делать простые вещи; возможно делать сложные вещи; и невозможным или, по крайней мере, трудным, делать неправильные вещи.

Хотя, как указано ниже, это действительно зависит от целевой аудитории


Множество простых в использовании шаблонов конструкций вызывает много критики (шаблон контекста, шаблон Singleton, шаблон с постоянным интерфейсом). Черт, даже принципы проектирования, такие как закон деметтера, подвергаются критике за слишком многословную.

Я бы не хотел этого говорить, но такие решения основаны на мнениях. Хотя шаблон контекста рассматривается как анти-шаблон, он проявляется в основных инфраструктурах, таких как Spring и Android SDK. Это сводится к окружающей среде, а также к целевой аудитории.

Основной недостаток, который я могу найти, указан в третьем списке под "минусами" в Constant Interface wiki:

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

Если вы когда-нибудь рисуете "Эй, это на самом деле не контракт, и я хочу обеспечить более сильный дизайн", вы не сможете его изменить. Но, как я уже сказал, это зависит от вас; возможно, вы не захотите изменить его в будущем.

Кроме того, ясность кода, упомянутая @TagirValeev. Интерфейсы должны быть реализованы; если вы не хотите, чтобы кто-то реализовал API, который вы поставляете, не делайте его выполнимым. Но я считаю, что это вращается вокруг заявления "целевой аудитории". Не собираюсь лгать, я с тобой на менее богатой основе, но это зависит от того, для кого мой код; не хотел бы использовать постоянный интерфейс для кода, который может быть рассмотрен.

Ответ 2

Вы должны использовать интерфейс только в том случае, если вы ожидаете, что кто-то его выполнит. Например, интерфейс java.util.stream.Stream имеет кучу статических методов, которые могут быть расположены в некоторых классах Streams или StreamUtils до Java 8. Однако это действительный интерфейс, который также имеет нестатические методы и может быть реализован. java.util.Comparable - еще один пример: все статические методы там поддерживают интерфейс. Вы не можете запрещать пользователям реализовывать свой публичный интерфейс, но для класса утилиты вы можете запретить им создавать его. Таким образом, для ясности кода я предлагаю не использовать интерфейсы, если они не предназначены для реализации.

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

Ответ 3

Я думаю, это сработает. Я думаю, что переменная SOME_CONSTANT по умолчанию статична в вашем SomeUtilityInterface, хотя вы этого явно не указали. Таким образом, это будет работать как Утилита, но не будет ли у вас некоторых проблем с изменчивостью, которых у вас не было бы с обычным классом, причем все переменные-члены должны быть окончательными? Пока это не проблема с вашей конкретной реализацией методов по умолчанию, я не могу придумать проблему.

Ответ 4

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

public class Utility {

    private Utility() {}

    public static final Map<String, Integer> MAP_CONSTANT;
    static {
        Map<String, Integer> map = new HashMap<>();
        map.put("zero", 0);
        map.put("one", 1);
        map.put("three", 3);
        MAP_CONSTANT = Collections.unmodifiableMap(map);
    }

    private static String PRIVATE_CONSTANT = "Hello, ";

    public static String hello(String name) {
        return PRIVATE_CONSTANT + name;
    }
}