具有实例的枚举结构?

时间:2012-08-10 10:08:09

标签: java enums

我使用以下枚举类型:

enum Status {OK,TIMEOUT,EXCEPTION}

但现在我想存储Exception究竟是什么。遗憾的是,您无法实例化枚举类型。制作类似下列内容的最佳方法是什么?

switch(status)
{
 case(OK)        {System.out.println("Everything OK!");break;}
 case(TIMEOUT)   {System.out.println("Timeout :-(");break;}
 case(EXCEPTION) {System.out.println("We have an exception: "+status.exception);break;}
}

我的想法

  1. 单身人士课程

    class Status
    {
     final Exception e;
     public final Status OK = new Status(null);
     public final Status TIMEOUT = new Status(null);
     public Status(Exception e) {this.e=e;}
    }
    
  2. 然后我可以做:

     if(status==Status.OK) {System.out.println("Everything OK!");}
     else if(status==Status.TIMEOUT) {System.out.println("Timeout :-(");}
     else {System.out.println("We have an exception: "+status.exception);}
    

    2。几个类

    class Status {}
    class StatusOK extends Status {}
    class StatusTimeout extends Status {}
    class StatusException extends Status
    {
     final Exception e;    
     public StatusException(Exception e) {this.e=e;}    
    }
    

    然后我需要一堆“instanceOf”-statements。

    P.S。:好吧好像我没有说清楚。在我的程序中,我回答请求,并存储处理这些请求的状态:

    Map<Request,Status> request2Status;
    

    因此我不能使用Status.getMessage(exception)之类的东西;因为在我的代码中的那个位置我不知道它是哪个例外。这就是为什么我要将保存在状态。

    选择解决方案

    private static class LearnStatus implements Serializable
        {               
            private static final long   serialVersionUID    = 1L;
            public static final LearnStatus OK = new LearnStatus(null);
            public static final LearnStatus TIMEOUT = new LearnStatus(null);
            public static final LearnStatus NO_TEMPLATE_FOUND = new LearnStatus(null);
            public static final LearnStatus QUERY_RESULT_EMPTY = new LearnStatus(null);
            public static final LearnStatus NO_QUERY_LEARNED = new LearnStatus(null);
    
            public final Exception exception;
    
            private LearnStatus(Exception exception) {this.exception = exception; }
    
            public static LearnStatus exceptionStatus(Exception cause)
            {
                if (cause == null) throw new NullPointerException();
                return new LearnStatus(cause);
            }
    
            @Override public String toString()
            {
                if(this==OK) {return "OK";}
                if(this==TIMEOUT) {return "timeout";}
                if(this==NO_TEMPLATE_FOUND) {return "no template found";}
                if(this==QUERY_RESULT_EMPTY) {return "query result empty";}
                if(this==NO_QUERY_LEARNED) {return "no query learned";}
                return "<summary>Exception: <details>"+exception.getLocalizedMessage()+"</details></summary>"; 
            }
        }
    

    有问题

    如果我序列化了包含Status.OK的对象,则在反序列化后if(status==Status.OK)不再有效。

    新解决方案

    我现在在课程中包含了一个枚举类型。你觉得怎么样?

    private static class LearnStatus implements Serializable
        {
            public enum Type {OK, TIMEOUT, NO_TEMPLATE_FOUND,QUERY_RESULT_EMPTY,NO_QUERY_LEARNED,EXCEPTION}
    
            public final Type type;
    
            private static final long   serialVersionUID    = 1L;
            public static final LearnStatus OK = new LearnStatus(Type.OK,null);
            public static final LearnStatus TIMEOUT = new LearnStatus(Type.TIMEOUT,null);
            public static final LearnStatus NO_TEMPLATE_FOUND = new LearnStatus(Type.NO_TEMPLATE_FOUND,null);
            public static final LearnStatus QUERY_RESULT_EMPTY = new LearnStatus(Type.QUERY_RESULT_EMPTY,null);
            public static final LearnStatus NO_QUERY_LEARNED = new LearnStatus(Type.NO_QUERY_LEARNED,null);
    
            public final Exception exception;
    
            private LearnStatus(Type type, Exception exception) {this.type=type;this.exception = exception;}
    
            public static LearnStatus exceptionStatus(Exception cause)
            {
                if (cause == null) throw new NullPointerException();
                return new LearnStatus(Type.EXCEPTION,cause);
            }
    
            @Override public String toString()
            {
                switch(type)
                {
                    case OK:                return "OK";
                    case TIMEOUT:           return "timeout";
                    case NO_TEMPLATE_FOUND: return "no template found";
                    case QUERY_RESULT_EMPTY:return "query result empty";
                    case NO_QUERY_LEARNED:  return "no query learned";
                    case EXCEPTION:         return "<summary>Exception: <details>"+exception.getLocalizedMessage()+"</details></summary>";
                    default: throw new RuntimeException("switch type not handled");
                }           
            }
        }
    

2 个答案:

答案 0 :(得分:3)

除非一切正常,否则我会使用Exception。

   System.out.println("Everything OK!");
} catch(TimeoutException te) {
   System.out.println("Timeout :-(")
} catch(Exception e) {
   System.out.println("We have an exception: " + e);
}

当Exceptions被设计为执行此类操作时,我认为不需要使用enum


在您和原始异常之间的图层顶部添加另一个图层,您可以执行此操作。

interface Status {
   String getMessage();
}

enum Statuses implements Status {
   OK("Everything OK"), TIMEOUT("Timeout :-(");

   private final String message;
   private Statuses(String message) { this.message = message; }

   String getMessage() { return message; }
}

class ExceptionStatus implement Status {
   private final String message;
   String getMessage() { return "Exception: " + message; }
}

// to print the message
System.out.println(status.getMessage());

答案 1 :(得分:1)

有几种方法,但所有这些方法都取决于您不使用Enums或不使用它们。请记住,枚举基本上是一个只有明确定义的单例作为值的类。

一种可能的重构是使用具有定义明确的单例而不是枚举的普通类:

class Status implements Serializable {
  // for serialization
  private enum InternalStatus {
    OK, TIMEOUT, EXCEPTION
  }
  public static final Status OK = new Status(null, InternalStatus.OK);
  public static final Status TIMEOUT = new Status(null, InternalStatus.TIMEOUT);

  private final Exception exception;
  private final InternalStatus internalStatus;

  private Status(Exception exception, InternalStatus internalStatus) {
    this.exception = exception;
    this.internalStatus = internalStatus;
  }

  public Exception getException() {
    return exception;
  }

  public static Status exceptionStatus(Exception cause) {
    if (cause == null) throw new NullPointerException();
    return new Status(cause, InternalStatus.EXCEPTION);
  }

  // deserialization logic handling OK and TIMEOUT being singletons
  private final Object readResolve() {
    switch (internalStatus) {
    case InternalStatus.OK:
      return OK;
    case InternalStatus.TIMEOUT:
      return TIMEOUT;
    default:
      return this;
    }
  }      
}

您现在可以查看status == Status.OKstatus == Status.TIMEOUT。如果您的状态变量既不正常也不是TIMEOUT,则必须由异常引起,您可以通过getException检索该异常。

作为缺点,您将失去switch功能,必须通过if进行检查。