使用继承

时间:2016-02-02 09:19:04

标签: java enums error-code

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

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将代码中的错误代码与其消息相关联。

4 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:0)

您的方法的组合可能正是您所寻找的:

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

答案 2 :(得分:0)

有必要使用某些样板代码,但您可以通过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);
}

答案 3 :(得分:0)

希望你能对此有所了解:

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