Лучший способ вернуть флаг состояния и сообщение из метода в Java - PullRequest
26 голосов
/ 10 декабря 2008

У меня обманчиво простой сценарий, и я хочу простое решение, но не очевидно, что является «наиболее правильным» или «наиболее Java».

Допустим, у меня есть небольшой метод аутентификации (клиент-клиент) в каком-то классе. Аутентификация может быть неудачной по ряду причин, и я хочу вернуть простое логическое значение для потока управления, но также вернуть сообщение String для пользователя. Вот те возможности, о которых я могу подумать:

  • Вернуть логическое значение и передать StringBuilder для сбора сообщения. Это самый близкий к C-стилю способ сделать это.
  • Бросьте исключение вместо возврата false и включите сообщение. Мне это не нравится, так как неудача не является исключительной.
  • Создайте новый класс с именем AuthenticationStatus с логическим значением и строкой. Это кажется излишним для одного маленького метода.
  • Сохранить сообщение в переменной-члене. Это может привести к состоянию потенциальной расы, и мне не нравится, что оно подразумевает некое состояние, которого на самом деле нет.

Любые другие предложения?

Редактировать Эта опция отключена

  • Вернуть ноль для успеха - это небезопасно?

Редактировать Решение:

Я выбрал самое ОО-решение и создал небольшой класс AuthenticationResult. Я бы не стал делать это на любом другом языке, но мне нравится это на Java. Мне тоже понравилось предложение возврата String [], поскольку это похоже на нулевой возврат, но безопаснее. Одним из преимуществ класса Result является то, что вы можете получить сообщение об успехе с дополнительной информацией, если требуется.

Ответы [ 17 ]

13 голосов
/ 10 декабря 2008

Вы можете использовать исключения ....

try {
    AuthenticateMethod();
} catch (AuthenticateError ae) {         
    // Display ae.getMessage() to user..
    System.out.println(ae.getMessage());
    //ae.printStackTrace();    
}

и затем, если в вашем AuthenticateMethod возникает ошибка, вы отправляете новую ошибку AuthenticateError (расширяет исключение)

10 голосов
/ 10 декабря 2008

Возврат небольшого объекта с логическим флагом и строкой внутри, вероятно, является наиболее ОО-подобным способом сделать это, хотя я согласен, что в таком простом случае, как этот, это кажется избыточным.

Другая альтернатива - всегда возвращать строку и иметь нулевое значение (или пустую строку - вы выбираете, какая) указывает на успех. Пока возвращаемые значения четко объяснены в javadocs, не должно быть никакой путаницы.

8 голосов
/ 10 декабря 2008

Избегайте возврата «часового значения», особенно ноль. В итоге вы получите кодовую базу, в которой вызывающая сторона не сможет понять методы, не прочитав реализацию. В случае нулевого значения вызывающие могут получить исключение NullPointerException, если они забудут (или не знают), что ваш метод может вернуть нулевое значение.

Предложение кортежа от Bas Leijdekkers является хорошим, которым я все время пользуюсь, если хочу вернуть более одного значения из метода. Мы используем P2<A, B> из библиотеки Functional Java . Этот тип типа является объединением двух других типов (он содержит одно значение каждого типа).

Создание исключений для потока управления - это немного запах кода, но проверенные исключения являются одним из способов получения более одного типа значения из метода. Хотя есть и другие, более чистые возможности.

  1. Вы можете иметь абстрактный класс Option<T> с двумя подклассами Some<T> и None<T>. Это немного похоже на безопасную альтернативу null и является хорошим способом реализации частичных функций (функций, возвращаемое значение которых не определено для некоторых аргументов). Библиотека Functional Java имеет полнофункциональный класс Option, который реализует Iterable<T>, поэтому вы можете сделать что-то вроде этого:

    public Option<String> authenticate(String arg) {
       if (success(arg))
          return Option.some("Just an example");
       else
          return Option.none();
    }
    
    ...
    
    for(String s : authenticate(secret)) {
       privilegedMethod();
    }
    
  2. В качестве альтернативы вы можете использовать несвязанное объединение двух типов, как класс Either<L, R>. Он содержит одно значение типа L или R. Этот класс реализует Iterable<T> для L и R, поэтому вы можете сделать что-то вроде этого:

    public Either<Fail, String> authenticate(String arg) {
       if (success(arg))
          return Either.right("Just an example");
       else
          return Either.left(Fail.authenticationFailure());
    }
    
    ...
    
    Either<Fail, String> auth = authenticate(secret);
    for(String s : auth.rightProjection()) {
       privilegedMethod();
    }
    for(Fail f : auth.leftProjection()) {
       System.out.println("FAIL");
    }
    

Все эти классы P2, Option и Either полезны в самых разных ситуациях.

3 голосов
/ 10 декабря 2008

Еще несколько опций:

  • Возвращает отдельное значение перечисления для каждого типа ошибки. Объект enum может содержать сообщение
  • Возвращает int и имеет отдельный метод, который ищет соответствующее сообщение из массива
  • создать универсальный класс кортежа утилит, который может содержать два значения. Такой класс может быть полезен во многих других местах.

простой пример кортежа, для реальной реализации может потребоваться больше:

class Tuple<L, R> {

    public final L left;
    public final R right;

    public Tuple( L left, R right) {
        this.left = left;
        this.right = right;
    }
}
1 голос
/ 10 декабря 2008

Тот факт, что неудачная аутентификация является обычным явлением, не означает, что она не является исключительной.

По моему мнению, ошибки аутентификации - это случай использования poster-child для проверенных исключений. (Ну ... может быть, каноническое использование - это несуществование файла, но ошибка аутентификации близка # 2.)

1 голос
/ 10 декабря 2008

Я лично думаю, что создание нового класса с именем AuthenticationStatus с логическим значением и String является наиболее подходящим способом Java. И хотя это кажется излишним (что вполне может быть), оно кажется мне чище и легче для понимания.

1 голос
/ 10 декабря 2008

Вы можете вернуть коллекцию сообщений об ошибках, пустую, указывающую, что проблем не было. Это уточнение вашего третьего предложения.

0 голосов
/ 10 декабря 2008

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

Почти тот же вопрос выложен здесь и здесь

Попытка вернуть два значения из одной функции может вводить в заблуждение. Но, как показали попытки сделать это, это может быть очень полезно.

Определенно создание и небольшой класс с результатами должен быть правильным способом для продолжения, если это общий поток в приложении, как было опубликовано ранее.

Вот цитата о возврате двух значений из функции:

Что касается стиля программирования, эта идея не обращение к объектно-ориентированному языку программирования. Возврат объектов для представления результатов вычислений идиома для возврата нескольких значений. Немного предположить, что вы не должны объявлять классы для несвязанных значений, но ни один не должен значения возвращаются из одного метода.

Я нашел его в запросе функции для Java, чтобы разрешить несколько возвращаемых значений

см. Раздел «Оценка» от 2005-05-06 09: 40: 08

0 голосов
/ 10 декабря 2008

Вернуть объект. Это позволяет вам добавить дополнительные функциональные возможности в класс, если вам это нужно. Краткосрочные объекты в Java быстро создаются и собираются.

0 голосов
/ 10 декабря 2008

Скорее всего, я бы выбрал что-то вроде:

<code>
class SomeClass {
public int authenticate (Client client) {
//returns 0 if success otherwise one value per possible failure
}
public String getAuthenticationResultMessage (int authenticateResult) {}
//returns message associated to authenticateResult
}

При таком «дизайне» вы можете запросить сообщение только в случае сбоя аутентификации (я надеюсь, что это сценарий, который происходит в 99,99% времени;))

Также может быть полезно делегировать разрешение сообщений другому классу. Но это зависит от потребностей вашего приложения (в основном это нужно для i18n?)

...