2013-04-19 4 views
2

я создал два enum классы как синглтон:Java - Абстрактный базовый перечисление/класс для одноплодной

public enum A { 
    INSTANCE; 

    public void init(param p1, param p2) { 
    } 

    public void connect() { 
    } 

    public void disconnect() { 
    } 

    public bool isConnected() { 
    } 
} 

public enum B { 
    INSTANCE; 

    public void init(param p1) { 
    } 

    public void connect() { 
    } 

    public void disconnect() { 
    } 

    public bool isConnected() { 
    } 
} 

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

UPDATE 1: Я хотел бы поставить некоторые общие переменные-члены в базовом классе

UPDATE 2: Должен ли я просто изменить путь я определяющий синглтон?

+1

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

ответ

2

По java enum tutorial

Все перечислений неявно продлить java.lang.Enum. Поскольку Java не поддерживает множественное наследование, перечисление не может распространять что-либо еще.

Здесь интересно SO discussion, относящееся к этой теме.

2

Как сказал Намбари, вы не можете перечислить все. Однако то, что они пренебрегли, говорит, что вы можете иметь enum реализовать интерфейс, который выполняется как с классом с использованием ключевого слова реализует. Я сделал это на работе, и это очень полезно в правильной ситуации! Там пример здесь: http://javahowto.blogspot.co.uk/2008/04/java-enum-examples.html

0

Существует сладкий маленький класс называется DynamicObjectAdapterFactory отправленный Heinz Kabutz, который использует дженерик и отражение для адаптации объекта для реализации интерфейса, обеспечивая его с исходным классом, который уже реализует интерфейс.

Используя его, как показано ниже, вы можете обернуть свой INSTANCE в прокси. Конечно, результирующий объект больше не является enum, но он делает сохраняет все однотональности enum. Он также, очевидно, может использовать любой объект для реализации вашего интерфейса.

Я думаю, что это как можно ближе к enum, расширяющему класс.

Вот несколько тестовых кодов, которые, похоже, работают. Очевидно, что объект больше не является enum, но поскольку ваша цель была одиночной, это может быть приемлемым.

public class Test { 
    // To implement this. 
    public interface Implement { 
    public void init(); 

    public void connect(); 

    public void disconnect(); 

    public boolean isConnected(); 
    } 

    // An implementor that does implement. 
    public static class Implements implements Implement { 

    @Override 
    public void init() { 
    } 

    @Override 
    public void connect() { 
    } 

    @Override 
    public void disconnect() { 
    } 

    @Override 
    public boolean isConnected() { 
     return false; 
    } 
    } 

    // Extend the INSTANCE in this. 
    public enum Extend { 
    INSTANCE; 
    // Hold my adapted version - thus still a singleton. 
    public final Implement adaptedInstance; 

    Extend() { 
     // Use the constructor to adapt the instance. 
     adaptedInstance = DynamicObjectAdapterFactory.adapt(this, Implement.class, new Implements()); 
    } 
    } 

    // Provides an INSTANCE that has been extended by an Implements to implement Implement. 
    public static Implement getInstance() { 
    return Extend.INSTANCE.adaptedInstance; 
    } 

    public void test() { 
    System.out.println("Hello"); 
    Implement i = getInstance(); 

    } 

    public static void main(String args[]) { 
    new Test().test(); 
    } 
} 

Вот DynamicObjectAdapterFactory - я подправил его немного от оригинала - Я надеюсь, что доктор Kabutz не возражает.

public class DynamicObjectAdapterFactory { 
    // Use methods in adaptee unless they exist in target in which case use adapter. 
    // Implement target in passing. 
    public static <T> T adapt(final Object adaptee, 
          final Class<T> target, 
          final Object adapter) { 

    return (T) Proxy.newProxyInstance(
      Thread.currentThread().getContextClassLoader(), 
      new Class[]{target}, 
      new InvocationHandler() { 
     private final String name = 
       adaptee.getClass().getSimpleName() + "(" + adaptee.toString() + ")" 
       + "+" + adapter.getClass().getSimpleName() + "(" + adapter.toString() + ")"; 
     // The methods I wish to adapt. 
     private Map<MethodIdentifier, Method> adaptedMethods = new HashMap<>(); 

     { 
     // initializer block - find all methods in adapter object 
     Method[] methods = adapter.getClass().getDeclaredMethods(); 
     for (Method m : methods) { 
      // Keep a map of them. 
      adaptedMethods.put(new MethodIdentifier(m), m); 
     } 
     } 

     @Override 
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
     try { 
      // Has it been adapted? 
      Method otherMethod = adaptedMethods.get(new MethodIdentifier(method)); 
      if (otherMethod != null) { 
      return otherMethod.invoke(adapter, args); 
      } else { 
      return method.invoke(adaptee, args); 
      } 
     } catch (InvocationTargetException e) { 
      throw e.getTargetException(); 
     } 
     } 

     @Override 
     public String toString() { 
     StringBuilder s = new StringBuilder(); 
     // Really simple. May get more flexible later. 
     s.append("Adapted: ").append(name); 
     return s.toString(); 
     } 
    }); 
    } 

    private static class MethodIdentifier { 
    private final String name; 
    private final Class[] parameters; 

    public MethodIdentifier(Method m) { 
     name = m.getName(); 
     parameters = m.getParameterTypes(); 
    } 

    @Override 
    public boolean equals(Object o) { 
     // I am always equal to me. 
     if (this == o) { 
     return true; 
     } 
     // I cannot be equal to something of a different type. 
     if (!(o instanceof MethodIdentifier)) { 
     return false; 
     } 
     MethodIdentifier mid = (MethodIdentifier) o; 
     return name.equals(mid.name) && Arrays.equals(parameters, mid.parameters); 
    } 

    @Override 
    public int hashCode() { 
     return name.hashCode(); 
    } 
    } 
} 
Смежные вопросы