Подтвердить что ты не робот

Лучший способ вернуть флаг статуса и сообщение из метода в Java

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

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

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

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

Изменить Отключен этот параметр

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

Изменить Решение:

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

а затем, если в вашем AuthenticateMethod произошла ошибка, вы отправляете новый AuthenticateError (extends Exception)

Ответ 3

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

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

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

  • У вас может быть абстрактный класс Option<T> с двумя подклассами Some<T> и None<T>. Это немного напоминает альтернативу нулевому типу, и хороший способ реализовать частичные функции (функции, возвращаемое значение которых не определено для некоторых аргументов). Библиотека 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();
    }
    
  • В качестве альтернативы вы можете использовать развязанный союз двух типов, как класс 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 полезны в самых разных ситуациях.

Ответ 4

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

  • Возвращает отдельное значение перечисления для каждого типа сбоя. Объект 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;
    }
}

Ответ 5

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

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

Ответ 6

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

Ответ 7

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

Ответ 8

Я сам использую "крошечный класс", обычно с внутренним классом. Мне не нравятся аргументы для сбора сообщений.

Кроме того, если метод, который может выйти из строя, является "низким уровнем" - например, исходящий с сервера приложений или уровня базы данных, я бы предпочел вернуть Enum с возвратом, а затем перевести его в строку на Уровень GUI. Не пропускайте пользовательские строки на низком уровне, если вы когда-либо собираетесь интернационализировать свой код, потому что тогда ваш сервер приложений может отвечать только на одном языке за раз, а не на разных клиентах, работающих на разных языках.

Ответ 9

Это единственный метод, когда у вас есть такое требование? Если нет, просто сгенерируйте общий класс Response с флагом isSuccessful и строкой сообщения и используйте это везде.

Или вы могли бы просто вернуть метод null, чтобы показать успех (не очень, и не позволяет вернуть успех и сообщение).

Ответ 10

Я бы, скорее всего, пошел на что-то вроде:


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?)

Ответ 11

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

Почти тот же вопрос размещен здесь и здесь

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

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

Здесь приведена цитата о возврате двух значений из функции:

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

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

посмотрите раздел "Оценка" от: 2005-05-06 09:40:08

Ответ 12

Успешная аутентификация должна быть "нормальным" случаем, поэтому исключительный случай является ошибкой аутентификации.

Каковы разные строки состояния для пользователя в любом случае. Я вижу только два, успех или неудачу. Любая дополнительная информация является потенциальной проблемой безопасности. Другим преимуществом решения с исключениями является то, что его нельзя назвать неправильным, а случай сбоя более очевиден. Без исключений вы пишете:

if (authenticate()) {
  // normal behaviour...
}
else {
  // error case...
}

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

authenticate();
// normal behaviour...

Если вы используете исключения, этого не может быть. Если вы решили не использовать исключения, по крайней мере, назовите метод, чтобы было ясно, что он возвращает состояние, e. г:.

if (isAuthenticated()) {
//...
}

Ответ 13

Здесь есть много хороших ответов, поэтому я буду держать его в курсе.

Я думаю, что отказ пользователя для аутентификации может считаться действительным случаем для проверенного исключения. Если ваш стиль программирования благоприятствовал обработке исключений, тогда не было бы причин не делать этого. Он также удаляет "Как вернуть несколько значений из метода, мой метод делает одно, что он аутентифицирует пользователя"

Если вы собираетесь возвратить несколько значений, потратите 10 минут на создание общего PairTuple (также может быть больше пары TripleTuple, я не буду повторять приведенный выше пример) и возвращать ваши значения таким образом. Мне не нравятся объекты с маленьким dto-объектом, чтобы возвращать различные значения, которые они просто загромождают.

Ответ 14

Как вернуть строку. Пусто или Нуль для успеха. Сообщение об ошибке в случае сбоя. Проще всего это сработает. Однако не уверен, что он хорошо читается.

Ответ 15

Я бы выбрал вариант Exception на первом месте.

Но, на втором месте, я бы предпочел технику C-стиля:

public boolean authenticate(Client client, final StringBuilder sb) {
    if (sb == null)
        throw new IllegalArgumentException();
    if (isOK()) {
        sb.append("info message");
        return true;
    } else {
        sb.append("error message");
        return false;
    }
}

Это не так странно, и это делается во многих местах в рамках.

Ответ 16

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

Ответ 17

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

public static void main(String[] args)
{
    Object[] result = methodReturningStatus();
    if(!(Boolean)result[0])
        System.out.println("Method return: "+ result[1]);
}

static Object[] methodReturningStatus()
{
    Object[] result = new Object[2];

    result[0] = false;
    result[1] = "Error happened";

    return result;
}