2016-02-02 2 views
3

Я хочу моделировать некоторые коды ошибок. Классический подход перечислениеопределить коды ошибок в java с наследованием

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 
    } 

    ... 
} 

это не хорошо для меня, потому что у меня есть много модулей, каждый с его коды ошибок, и я не хочу, чтобы скопировать и вставить шаблонного (конструкторы, Геттеры, логика ..) в все эти перечисления.

Так что я пошел на «ручной» перечислимый реализованных как этот

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), и люди, скопировавшие вставку, могут повторно использовать один и тот же номер, не замечая. Я мог бы добавить тест, чтобы проверить это с помощью рефлексии, но затем как заставить людей использовать этот тест для их реализации.

так вы, ребята, лучше знаете, как я мог это достичь?

[изменить] Пожалуйста, имейте в виду, что я не хочу помещать коды ошибок в файлы свойств, потому что я хочу, чтобы ide связывал коды ошибок в коде с их сообщением.

+0

Интеграционных тесты должны проверить, что никаких цифр не используются повторно, предпочитаемые, эти тесты должен запускаться сразу после тестирования модуля, чтобы тест мог использовать 'BaseError.class.getSubClasses()', чтобы быстро получить все подтипы. – Ferrybig

+0

Возможный дубликат [Лучший способ определения кодов ошибок/строк в Java?] (Http: // stackoverflow.com/questions/446663/best-way-to-define-error-codes-strings-in-java) – vels4j

ответ

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.

+0

это полезно спасибо – alex

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