Рубрики
Без рубрики

Эффективная Java! Эмулируйте Расширяемые Перечисления С Помощью Интерфейсов.

Погружение в главу 38 “Эффективная Java”. Помеченный как java, эффективный, перечисление, архитектура.

Эффективный обзор Java (Серия из 79 частей)

Мы продолжаем углубляться в различные соображения при работе с перечислениями . Ранее в этой серии мы рассмотрели альтернативы использованию перечисления s. На протяжении предыдущих глав мы показывали, что перечисления являются предпочтительным методом. Есть одно место, где альтернативы использованию обычных классов превосходят перечисление s, а именно расширение существующей функциональности. По уважительной причине тип перечисление не допускает расширения.

При этом бывают случаи, когда нам может понадобиться функциональность такого типа, особенно при работе с перечислениями , которые представляют разные операции. В предыдущей главе мы рассматривали этот вариант использования с нашим классом калькулятора и использованием операции перечисления. К счастью, есть способ имитировать поведение расширения с помощью интерфейсов. Давайте посмотрим, как это будет выглядеть с нашим перечислением Operation .

public interface Operation {
  double apply(double x, double y);
}

public enum BasicOperation implements Operation {
  PLUS("+") {
    public double apply(double x, double y) { return x + y; }
  },
  MINUS("-") {
    public double apply(double x, double y) { return x - y; }
  },
  TIMES("*") {
    public double apply(double x, double y) { return x * y; }
  },
  DIVIDE("/") {
    public double apply(double x, double y) { return x / y; }
  };

  private final String symbol;

  BasicOperation(String symbol) {
    this.symbol = symbol;
  }

  @Override
  public String toString() {
    return symbol;
  }
}

Хотя фактическое перечисление Базовая операция не является расширяемым, через интерфейс мы можем в некоторой степени имитировать поведение расширяемости. Например, мы можем определить новое перечисление , которое реализует интерфейс Операции и может использоваться вместо базовой операции . Это может выглядеть примерно так:

public enum ExtendedOperation implements Operation {
  EXPONENT("^") {
    public double apply(double x, double y) {
      return Math.pow(x, y);
    }
  },
  REMAINDER("%") {
    public double apply(double x, double y) {
      return x % y;
    }
  };

  private final String symbol;

  ExtendedOperation(String symbol) {
    this.symbol = symbol;
  }

  @Override
  public String toString() {
    return symbol;
  }
}

Итак, как вы можете видеть, мы снова реализуем интерфейс Operation , это позволяет нам использовать это перечисление в том же месте, что и другое наше перечисление, в котором реализован Операция . Теперь давайте посмотрим, как это можно использовать.

public static void main(String[] args) {
  double x = Double.parseDouble(args[0]);
  double y = Double.parseDouble(args[1]);
  test(ExtendedOperation.class, x, y);
}

private static  & Operation> void test(Class opEnumType, double x, double y) {
  for (Operation operation : opEnumType.getEnumConstants()) {
    System.out.printf("%f %s %f = %f%n", x, operation, y, operation.apply(x, y));
  }
}

Теперь я буду первым, кто признает, что это довольно интенсивное объявление типа, в основном это просто означает, что нам нужен перечисление , которое реализует интерфейс Operation . При этом вы должны быть в состоянии увидеть, как мы могли бы передать любой тип перечисления этому методу и заставить его работать.

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

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

Эффективный обзор Java (Серия из 79 частей)

Оригинал: “https://dev.to/kylec32/effective-java-emulate-extensible-enums-with-interfaces-4o7d”