【问题标题】:java - Abstract base enum/class for singletonjava - 单例的抽象基枚举/类
【发布时间】:2013-04-19 20:03:43
【问题描述】:

我创建了两个 enum 类作为单例:

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() {
    }
}

您可以看到两个枚举类非常相似,所以我想知道是否应该创建某种基本抽象类/枚举或接口,然后让这两个枚举从中扩展或实现。

更新1:我想把一些共享成员变量放在基类上

更新 2:我应该改变定义单例的方式吗?

【问题讨论】:

  • 枚举不能扩展任何东西。但是,您可以让它们实现一个通用接口。

标签: java enums singleton abstract base


【解决方案1】:

根据java enum tutorial

所有枚举都隐式扩展 java.lang.Enum。由于Java没有 支持多重继承,枚举不能扩展其他任何东西。

这里有一个有趣的SO discussion 与此主题相关。

【讨论】:

    【解决方案2】:

    正如 Nambari 所说,您不能让枚举扩展任何内容。但是他们忽略了说的是你可以让一个枚举实现一个接口,这就像使用 implements 关键字的类一样。我在工作中做过这个,它在正确的情况下非常有用!这里有一个例子:http://javahowto.blogspot.co.uk/2008/04/java-enum-examples.html

    【讨论】:

      【解决方案3】:

      Heinz Kabutz 发布了一个名为DynamicObjectAdapterFactory 的可爱小类,它使用泛型和反射来调整对象以实现接口,方法是为对象提供已经实现接口的源类。

      像下面这样使用它,您可以将您的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();
          }
        }
      }
      

      【讨论】:

        【解决方案4】:

        您可以将下面的抽象类用于单例而不是枚举。

        public abstract class AbstractSingleton {
        
            private static Map<String, AbstractSingleton> registryMap = new HashMap<String, AbstractSingleton>();
        
            AbstractSingleton() throws SingletonException {
                String clazzName = this.getClass().getName();
                if (registryMap.containsKey(clazzName)) {
                    throw new SingletonException("Cannot construct instance for class " + clazzName + ", since an instance already exists!");
                } else {
                    synchronized (registryMap) {
                        if (registryMap.containsKey(clazzName)) {
                            throw new SingletonException("Cannot construct instance for class " + clazzName + ", since an instance already exists!");
                        } else {
                            registryMap.put(clazzName, this);
                        }
                    }
                }
            }
        
            @SuppressWarnings("unchecked")
            public static <T extends AbstractSingleton> T getInstance(final Class<T> clazz) throws InstantiationException, IllegalAccessException {
                String clazzName = clazz.getName();
                if (!registryMap.containsKey(clazzName)) {
                    synchronized (registryMap) {
                        if (!registryMap.containsKey(clazzName)) {
                            T instance = clazz.newInstance();
                            return instance;
                        }
                    }
                }
                return (T) registryMap.get(clazzName);
            }
        
            public static AbstractSingleton getInstance(final String clazzName)
                    throws ClassNotFoundException, InstantiationException, IllegalAccessException {
                if (!registryMap.containsKey(clazzName)) {
                    Class<? extends AbstractSingleton> clazz = Class.forName(clazzName).asSubclass(AbstractSingleton.class);
                    synchronized (registryMap) {
                        if (!registryMap.containsKey(clazzName)) {
                            AbstractSingleton instance = clazz.newInstance();
                            return instance;
                        }
                    }
                }
                return registryMap.get(clazzName);
            }
        
            @SuppressWarnings("unchecked")
            public static <T extends AbstractSingleton> T getInstance(final Class<T> clazz, Class<?>[] parameterTypes, Object[] initargs)
                    throws SecurityException, NoSuchMethodException, IllegalArgumentException,
                    InvocationTargetException, InstantiationException, IllegalAccessException {
                String clazzName = clazz.getName();
                if (!registryMap.containsKey(clazzName)) {
                    synchronized (registryMap) {
                        if (!registryMap.containsKey(clazzName)) {
                            Constructor<T> constructor = clazz.getConstructor(parameterTypes);
                            T instance = constructor.newInstance(initargs);
                            return instance;
                        }
                    }
                }
                return (T) registryMap.get(clazzName);
            }
        
            static class SingletonException extends Exception {
                private static final long serialVersionUID = -8633183690442262445L;
        
                private SingletonException(String message) {
                    super(message);
                }
            }
        }
        

        发件人:https://www.cnblogs.com/wang9192/p/3975748.html

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-10-01
          • 1970-01-01
          • 1970-01-01
          • 2013-03-13
          • 1970-01-01
          相关资源
          最近更新 更多