【问题标题】:define error codes in java with inheritance用继承在java中定义错误代码
【发布时间】:2016-05-11 00:16:17
【问题描述】:

我想对一些错误代码进行建模。经典的枚举方法

public enum FileError implement FormattedError {
    _10 ("some error with parameters [{0}] and [{1}]"),
    _20 ("some other error");

    private final String description;

    private Error(String description) {
        this.description = description;
    }

    public String getDescription(Object... parameters) {
        return // logic to format message 
    }

    ...
}

这对我不好,因为我有很多模块,每个模块都有错误代码,我不想在所有这些枚举中复制和粘贴样板文件(构造函数、getter、逻辑..)。

所以我选择了一个像这样实现的“手动”枚举

public class FileError extends BaseError {

    public final static FileError _10  = new FileError (10, "some message with parameters [{0}] and [{1}]");
    public final static FileError _20  = new FileError (20, "some other message");

}

我可以在 BaseError 中定义我的逻辑并重用它。

但它仍然很糟糕,因为没有办法将变量名链接到数字(_10 到 10),而且人们复制粘贴可能会在不注意的情况下重复使用相同的数字。我可以添加一个测试来通过反射来检查它,但是我如何强制人们使用该测试来实现他们的实现。

那么你们对我如何实现这一点有更好的想法吗?

[edit] 请记住,我不想将错误代码放在属性文件中,因为我希望 ide 将代码中的错误代码与其消息链接。

【问题讨论】:

  • 集成测试应该验证没有数字被重用,最好是这些测试应该在单元测试之后直接运行,这样测试就可以使用BaseError.class.getSubClasses()快速获取所有子类型。

标签: java enums error-code


【解决方案1】:

要回答您关于如何检查重复使用号码的问题,您可以简单地通过使用到目前为止已注册的所有号码的静态集合来完成此操作,并检查在注册新号码时它是否还不存在:

public class BaseError {
    // ...

    private static Set<Integer> registeredNums = new HashSet<>();

    public BaseError(int N, String msg) {
        synchronized(registeredNums) {
            assert(!registeredNums.contains(N)) : "Duplicated error code";
            registeredNums.add(N);
        }

        // ...
    }
}

用户需要启用断言。如果您希望检查始终发生,您可以手动抛出AssertionError

【讨论】:

    【解决方案2】:

    这两种方法的组合可能就是您想要的:

    enum ErrorCode {
      _10(new FileError(10, "some message with parameters [{0}] and [{1}]")),
      _20(new FileError(20, "some other message"));
    
      private final FileError error;
    
      private ErrorCode(FileError err) {
        error = err;
      }
    
      public FileError getError() {
        return error;
      }
    }
    

    使用此代码,错误代码和变量之间存在显式链接。为了避免其他人使用相同的错误代码,您可以通过将构造函数包设为私有来完全阻止他们创建自己的 FileError 实例。如果这不是一个选项,您可以创建一个额外的子类,如下所示:

    public class UserDefinedFileError extends FileError {
      public UserDefinedFileError(int code, String msg){
        super(checkCode(code),msg);
      }
    
      static int checkCode(int code){
        if(code <= 100){ // or check if it exists in a set of used codes
          throw new IllegalArgumentException("Error codes lower than 100 are reserved.");
        }
      }
    }
    

    【讨论】:

      【解决方案3】:

      有必要使用一些样板代码,但您可以通过使enum 实现interface 并将大部分功能静态地放在interface 中来将其保持在最低限度 -当然,假设您使用的是 Java-7+。

      interface Error {
      
          /**
           * Keeps track of error ranges - for sanity check when errors are registered.
           */
          static final Map<ErrorRange, Set<? extends Error>> errors = new HashMap<>();
          /**
           * Lookup range.
           */
          static final Map<Error, ErrorRange> range = new HashMap<>();
      
          public static <E extends Enum<E> & Error> void register(ErrorRange errorRange, Class<E> theClass) {
              // Keep track of all errors - TODO - Make sure each is registered only once.
              errors.put(errorRange, EnumSet.allOf(theClass));
              // We need the range.
              for (Error e : theClass.getEnumConstants()) {
                  range.put(e, errorRange);
              }
          }
      
          /**
           * Get a formatted string for the error with the provided parameters.
           */
          static <E extends Enum<E> & Error> String format(E error, Object... parameters) {
              // The error number comes from it's range + its ordinal.
              int errNo = range.get(error).range + error.ordinal();
              // The string comes from the formatted description.
              return errNo + "\t" + String.format(error.getDescription(), parameters);
          }
      
          // All Errors must have a description.
          public String getDescription();
      
      }
      
      /**
       * Register of all error ranges.
       */
      enum ErrorRange {
      
          // All File errors start at 10,000
          FileError(10_000);
      
          final int range;
      
          private ErrorRange(int range) {
              this.range = range;
          }
      
      }
      
      public enum FileError implements Error {
      
          ParameterError("some error with parameters [{0}] and [{1}]"),
          OtherError("some other error");
      
          //<editor-fold defaultstate="collapsed" desc="Description">
          // Start boilerplate
          private final String description;
      
          private FileError(String description) {
              this.description = description;
          }
      
          @Override
          public String getDescription() {
              return description;
          }
          // End boilerplate
          //</editor-fold>
      
      }
      
      static {
          // Statically register me with the Error object.
          Error.register(ErrorRange.FileError, FileError.class);
      }
      

      【讨论】:

        【解决方案4】:

        希望您对此有所了解:

        public enum FileError {
            SOME_ERROR1("0", "Error something1"),
            SOME_ERROR2("1", "Error something2"),
            SOME_ERROR3("2", "Error something3"),
        
            private final String code;
            private final String message;
        
            FileError(String code, String message) {
                this.code = code;
                this.message = message;
            }
        
            public String get() {
                return new CustomException(code, message).toString();
            }
        }
        

        你是CustomException

        public class CustomException {
        
            ...
        
            @Override
            public String toString() {
                return String.format(Locale.getDefault(), "%s, %s", code, message);
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2016-03-19
          • 2014-06-20
          • 2020-02-06
          • 2015-10-14
          • 2014-09-15
          • 2014-01-01
          • 1970-01-01
          • 2021-10-13
          • 2019-11-16
          相关资源
          最近更新 更多