Подклассирование перечисления
существует простой способ подкласса Java enum
?
Я спрашиваю об этом, потому что у меня есть 10 из них, которые реализуют один и тот же интерфейс, но они также имеют одну и ту же реализацию для некоторых методов, поэтому я хотел бы повторно использовать код, помещая все те же реализации в средний объект, который расширяет enum
и это также суперкласс всех остальных, в которых я нуждаюсь.
Может, это не так просто, как я думаю?
Спасибо заранее
Ответы
Ответ 1
Вы не можете этого сделать, поскольку язык вас не позволяет. И для хорошей логической причины: подклассификация перечисления имела бы смысл только в том случае, если вы могли бы удалить некоторые значения перечисления из подкласса, а не добавлять новые. В противном случае вы нарушите Принцип замены Лискова.
Вкратце говорится, что каждый экземпляр подкласса должен быть приемлемым всякий раз, когда ожидается экземпляр суперкласса. Если вы добавите новый член перечисления в подкласс enum, который явно не может быть принят кем-то, зная только супер перечисление.
Более подробную информацию и возможные альтернативы см. этот более ранний ответ.
В вашем конкретном случае предложение @Jason может предложить хорошее решение (+1 для него: -)
Обновить до комментария @OrangeDog
Хорошая мысль, я был немного неряшливым:-) Внедрение - вы правы. Однако с логической точки зрения тип перечисления полностью описывается набором его допустимых значений. И вообще, надлежащий подкласс является специализацией его суперкласса. Другими словами, набор допустимых экземпляров подкласса (должен быть) всегда является подмножеством набора экземпляров суперкласса. (Каждая собака - животное, но не каждое животное - собака.)
Ответ 2
Я спрашиваю об этом, потому что у меня есть 10 из них, которые реализуют один и тот же интерфейс, но у них также есть одна и та же реализация для некоторых методов, поэтому я хотел бы повторно использовать код, помещая все те же реализации в средний объект, который расширяет Enum, и это также является суперклассом всех остальных, которые мне нужны.
Как использовать статический вспомогательный класс?
interface Animal
{
public void speak();
}
class AnimalHelper
{
public static void speakHelper(Animal animal) {
// common methods here
}
}
enum Dog implements Animal { SCHNAUZER, LABRADOR, ST_BERNARD, DACHSHUND;
@Override public void speak() {
AnimalHelper.speakHelper(this);
}
};
enum Bird implements Animal { OWL, FINCH, DUCK, GOOSE; }
@Override public void speak() {
AnimalHelper.speakHelper(this);
}
};
Ответ 3
С помощью Java 8 вы можете поместить общую реализацию в интерфейс, используя методы по умолчанию.
public class DefaultMethodOnEnumInterface {
public interface Greeter {
default public void greet() {
System.out.println("Hello, world!");
}
}
public enum Greeters implements Greeter {
A,
B;
}
public static void main(String[] args) {
Greeters.A.greet();
Greeters.B.greet();
}
}
Если требуется доступ к методам, реализованным классом Enum
, добавьте подпись в интерфейс:
public interface Greeter {
default public void greet() {
System.out.println("Hello, world! This is " + name());
}
/**
* @see Enum#name()
*/
public String name(); // implemented by Enum
}
Ответ 4
Хотя в Java были предложения для абстрактных перечислений, преимущества считаются слишком низкими, чтобы перевесить затраты. Вам придется придерживаться вызовов метода переадресации.
Ответ 5
Попробуйте использовать Enums из пакета общих пакетов Apache, где вы можете подклассы Enums.
Не знаю, поможет ли это вам.
Ответ 6
Язык не позволяет это сделать, поскольку Enums предназначены для эффективного представления нумерованных значений, а не для реализации кода. Попробуйте использовать другой шаблон, например, статический помощник (утилита).
Ответ 7
@Jason S предлагает хороший ответ, но статический метод заставляет вас потерять возможности ООП.
Как насчет делегации? Я имею в виду:
-
Определите общий интерфейс "I_A", где вы определяете все геттеры/сеттеры и все другие методы.
-
Определите "структурный" класс "S_C": он реализует только геттеры и сеттеры, другие методы пустые, потому что бесполезны.
-
Чтобы сделать ваши перечисления короче (с точки зрения строк кода), определите второй интерфейс "I_A_Delegating", который расширяет первые, имеет дополнительный getter/setter типа "I_A" (это наш делегат) и, благодаря методам Java по умолчанию, определите getter/setter как вызов получателя/сеттера делегата.
-
Все ваши перечисления реализуют "I_A_Delegating" и имеют локальный экземпляр "S_C"
Пример кода:
public class EnumFakeExtension{
/**"I_A"*/
public static interface CommonInterface{
public Object getFieldOne();
public Object getFieldTwo();
public void setFieldOne(Object o);
public void setFieldTwo(Object o);
public void someMethod();
}
/*"S_C"*/
public static class CommonDelegator_FieldKeeper implements CommonInterface{
Object oOne, oTwo;
public Object getFieldOne(){ return oOne; }
public Object getFieldTwo(){ return oTwo; }
public void setFieldOne(Object o){ oOne = o; }
public void setFieldTwo(Object o){ oTwo = o; }
public void someMethod(){ /*empty*/ }
}
/**"I_A_Delegating"*/
public static interface CommonInterface_Delegating extends CommonInterface{
public CommonInterface getDelegate();
public void setDelegate(CommonInterface delegator);
/**Just to simplify*/
public default void setDefaultDelegate(CommonInterface delegator){
setDelegate( new CommonDelegator_FieldKeeper() );
}
public default Object getFieldOne(){ return getDelegate().getFieldOne(); }
public default Object getFieldTwo(){ return getDelegate().getFieldTwo(); }
public default void setFieldOne(Object o){ getDelegate().setFieldOne(o); }
public default void setFieldTwo(Object o){ getDelegate().setFieldTwo(o); }
}
/*the enums, now*/
public static enum EnumFirst implements CommonInterface_Delegating{
FieldA, FieldB, FieldC;
EnumFirst (){
setDefaultDelegate();
}
final CommonDelegator_FieldKeeper delegator;
public CommonInterface getDelegate(){ return delegator; }
public void setDelegate(CommonInterface delegator){ this.delegator=delegator; }
public void someMethod(){
/*do what You need*/
}
}
public static enum EnumSecond implements CommonInterface_Delegating{
FieldA, FieldB, FieldC;
EnumSecond (){
setDefaultDelegate();
}
final CommonDelegator_FieldKeeper delegator;
public CommonInterface getDelegate(){ return delegator; }
public void setDelegate(CommonInterface delegator){ this.delegator=delegator; }
public void someMethod(){
/*do what You need, again*/
}
}
}