Несколько перечислений против одного enum
Я рассматривал пример реализации Publisher (AsyncIterablePublisher.java) спецификации реактивных потоков, когда я наткнулся на что-то, что я не понимаю, почему это было сделано таким образом.
static interface Signal {};
enum Cancel implements Signal { Instance; };
enum Subscribe implements Signal { Instance; };
enum Send implements Signal { Instance; };
enum Signal {
Cancel,
Subscribe,
Send;
}
может кто-нибудь объяснить мне, почему было бы лучше? Преимущества / недостатки?
5 ответов
не будьте слишком строги, вот моя интерпретация этого кода. Назовем владельца реактивных потоков Роландом.
сначала Роланду нужен общий интерфейс для всех inboundSignals
static interface Signal {};
ConcurrentLinkedQueue<Signal> inboundSignals = new ConcurrentLinkedQueue<Signal>();
сигналы, такие как Cancel
, Subscribe
и Send
всегда одна и та же цель неизменна и происходит очень часто, поэтому неплохо реализовать их как Синглтон Джошуа Блоха:
enum Cancel implements Signal { Instance; };
enum Subscribe implements Signal { Instance; };
enum Send implements Signal { Instance; };
другой способ сделать то же самое похоже на ваше предложение и мое любимое:
enum CommonSignals implements Signal{
Cancel {
@Override
void debug() {
System.out.println("Cancel");
}
},
Subscribe {
@Override
void debug() {
System.out.println("Subscribe");
}
},
Send {
@Override
void debug() {
System.out.println("Send");
}
};
abstract void debug();
[...] some other methods I could need in the future
}
как вы можете видеть, это другая реализация. Но идея та же-сигнал, что и синглтон
мы идем дальше и находим этот код:
static final class Request implements Signal {
final long n;
Request(final long n) { // every Request has different value of n
this.n = n;
}
};
С inboundSignals
может содержать несколько Request
объекты невозможно реализовать этот тип сигнала, как синглтон. Поэтому он не может быть членом CommonSignals
или реализуется в виде enum
.
вывод
Роланд использовал одну из многих возможностей для реализации синглтонов. Я думаю, что это больше вопрос вкуса, как это сделать.
для типа использования в AsyncIterablePublisher две формы эквивалентны, и, возможно, последнее, одно перечисление с несколькими константами, более естественно.
На самом деле, первая форма очень редка. Я вижу один аргумент в пользу его использования (но он настолько редок, что это означает, что этот момент обычно не так важен): когда вы определяете каждую константу в своем собственном перечислении, вы получаете возможность определить различные методы / поля, такие как:
enum Cancel implements Signal { Instance; };
enum Send implements Signal {
Instance;
public void someSendSpecificMethod() { ... }
}
Так что теперь вы можете сделать Send.Instance.someSendSpecificMethod()
. Очень неловко, очень редко.
разница в том, что вы можете добавить другие экземпляры сигнала без изменения исходного перечисления. Ваш код может работать с экземплярами сигналов, и могут быть предоставлены различные типы. То же самое, что интерфейс для классов - дает вам гибкость, но это полезно, только если вам это нужно. В вашем случае я не вижу большой пользы, потому что интерфейс пуст, а перечисления, реализующие его, ничего в них не имеют.
вы можете проверить этот сайт на хороший пример перечисления с интерфейсы:
http://www.selikoff.net/2011/06/15/java-enums-can-implement-interfaces/
Привет Майкл,
в чем разница с наличием только одного перечисления? У вас не было бы трех синглетов, но все же три однозначно определенных объекта.:
конечно, это можно сделать, но тогда мне придется придумай ему имя. (как ConcreteSignal), моя выбранная кодировка избегает этого:)
enum Signal {
Cancel, Subscribe, Send;
}
Я думаю, что это также потокобезопасно, и если вы действительно хотите иметь общий интерфейс, которым вы можете поделиться с объектами, например, вы можете сделать это так:
enum ConcreteSignal implements Signal {
Cancel,
Subscribe,
Send;
}
вы могли бы определенно сделать, как вы сделали выше, однако я бы поспорил, что они [отмена, подписка, отправка] не более конкретны, чем запрос (что также является сигналом): https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.0/examples/src/main/java/org/reactivestreams/example/unicast/AsyncIterablePublisher.java#L49
кроме того, это также может побудить использовать методы перечисления для перечислить все возможные сигналы, которые он не мог, так как запрос не сигнал. Смысл?
действительно, в Scala вы предпочли бы сделать это с объектом, но в Java очень редко можно увидеть что-то вроде вашего реализация. Мне было просто любопытно, что мне не хватает какой-то аккуратной функции на Java. Но если я правильно понимаю, это потому, что вам более комфортно с этой реализацией, поскольку она ближе к Scala, вашему предпочтительному языку?
Я думаю, что есть немного этого, но синглтон-как-перечисление-шаблон на Java довольно хорошо известно, поэтому единственной "странной" вещью было бы имейте отдельное "перечисление" для каждого из отмены, подписки и отправки, но как Я уже объяснял, поскольку запрос не может быть закодирован таким образом, я выбрал более "Scala-y" версию.
поэтому, если "запрос" не будет нуждаться в каких-либо параметрах, я бы сделал, как вы предложено: enum Signal { отмена, запрос, подписка, отправка }
Тайна раскрыта :-).
что я думаю, что единственная причина использования интерфейса с перечислением, что некоторые из сигналов имеют данные, отличные от других сигналов, поэтому ему нужно расширить тип перечисления, чтобы прикрепить к нему данные.