1

次の列挙型を使用します。

enum Status {OK,TIMEOUT,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;}
    }
    

次に、次のことができます。

 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」ステートメントが必要になります。

PS:わかりました、私はそれを十分に明確に説明していないようです。私のプログラムでは、リクエストに応答し、それらのリクエストの処理ステータスを保存します。

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");
            }           
        }
    }
4

2 に答える 2

3

すべてが問題ない限り、例外を使用します。

お気に入り

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

enumwhen 例外がこの種のことを行うように設計されている場合、使用する必要はないと思います。


あなたと元の例外の間のレイヤーの上にさらに別のレイヤーを追加すると、これを行うことができます。

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());
于 2012-08-10T10:13:35.510 に答える
1

これにはいくつかのアプローチがありますが、それらはすべて、列挙型を使用しないか、排他的に使用しないかによって異なります。列挙型は基本的に、明確に定義されたシングルトンのみを値として持つクラスであることに注意してください。

これの可能なリファクタリングの 1 つは、列挙型の代わりに明確に定義されたシングルトンを持つ通常のクラスを使用することです。

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.OKなりstatus == Status.TIMEOUTました。ステータス変数が OK でも TIMEOUT でもない場合は、例外が原因である必要があります。例外は で取得できますgetException

欠点として、switch機能が失われ、経由で確認する必要がありifます。

于 2012-08-10T10:17:33.910 に答える