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

Есть ли название для этого запаха анти-шаблона/кода?

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

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

class FunctionResult<T>
{
    public T payload;
    public int result;
}

И затем объявите свои функции следующим образом:

FunctionResult<string> MyFunction()
{
    FunctionResult<string> result;
    //...

    return result;
}

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

4b9b3361

Ответ 1

Я бы согласился, что это не совсем антипаттерн. Это может быть запах в зависимости от использования. Есть причины, по которым на самом деле не хотелось бы использовать исключения (например, возвращаемые ошибки не являются "исключительными" для стартеров).

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

Этот код может и не быть ошибкой: рассмотрите ответ HTTP, который состоит из множества разных данных, включая код состояния, вместе с телом ответа.

Ответ 3

Ну, это не антипаттерн. Стандартная библиотека С++ использует эту функцию, и .NET даже предлагает специальный класс FunctionResult в платформе .NET. Он назывался Nullable. Да, это не ограничивается результатами функции, но может быть использовано для таких случаев и на самом деле очень полезно здесь. Если .NET 1.0 уже имел класс Nullable, он, безусловно, использовался бы для методов NumberType.TryParse вместо параметра out.

Ответ 4

Я обычно передаю полезную нагрузку как ссылку (не const) и код ошибки в качестве возвращаемого значения.

Я разработчик игр, мы исключаем исключения

Ответ 5

Конрад прав, С# все время использует двойные возвращаемые значения. Но я вроде как методы TryParse, Dictionary.TryGetValue и т.д. На С#.

int value;
if (int.TryParse("123", out value)) {
    // use value
}

вместо

int? value = int.TryParse("123");
if (value != null) {
    // use value
}

... главным образом потому, что шаблон Nullable не масштабируется для типов возвращаемых значений (например, экземпляров класса). Это не будет работать с Dictionary.TryGetValue(). И TryGetValue лучше, чем KeyNotFoundException (нет "исключений из первых шансов" постоянно в отладчике, возможно более эффективный), лучше, чем практика Java get(), возвращающая значение null (что, если ожидаются нулевые значения), и более эффективно, чем сначала вызовите ContainsKey().

Но это все еще немного отвратительно - так как это выглядит как С#, тогда он должен использовать параметр out. Вероятно, все выгоды от повышения производительности теряются, создавая экземпляр класса.

(Может быть Java, за исключением того, что тип "string" находится в нижнем регистре. В Java, конечно, вы должны использовать класс для эмулирования двойных возвращаемых значений.)

Ответ 6

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

Ответ 7

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

Например, учитывая X количество газа, может ли автомобиль получить от А до В, и если да, то сколько газа осталось? Такой вопрос идеально подходит для структуры данных, которую вы предоставили. Невозможно сделать поездку с A на B, поэтому исключение не должно использоваться.

Ответ 8

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

Я потратил часы, пытаясь отладить код семафора на моем MacBook, прежде чем я узнал, что sem_init не работает на OSX! Он скомпилирован без ошибок и запускался без каких-либо ошибок, но семафор не работал, и я не мог понять, почему. Мне жаль людей, которые переносят приложение, которое использует семафоры POSIX для OSX и должно решать проблемы с конфликтом ресурсов, которые уже были отлажены.

Ответ 9

Как насчет шаблона "Невозможно решить, является ли это ошибкой или нет". Похоже, если у вас действительно было исключение, но вы хотели вернуть частичный результат, вы бы обернули результат в исключение.

Ответ 10

Если вы не хотите использовать исключения, самый чистый способ сделать это - вернуть функцию код ошибки/успеха и взять либо аргумент ссылки или указателя, который будет заполнен результатом.

Я бы не назвал это анти-шаблоном. Это очень хорошо зарекомендовавший себя работоспособный метод, который часто предпочтительнее использовать исключения.

Ответ 11

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

bool TryMyFunction(out FunctionResult result){    

     //...    
     result = new FunctionResult();
}

Ответ 12

Дискуссии о запахах и анти-шаблонах напоминают мне телешоу "Survivor", где у вас есть различные программные конструкции, пытающиеся проголосовать друг у друга на острове. Я бы предпочел увидеть, что "у конструкции X есть такие-то плюсы и минусы", а не на постоянно меняющийся список указаний о том, что должно и не должно быть сделано.

Ответ 13

В защиту обозначения анти-шаблона этот код может использоваться несколькими способами:

  • Объект x = MyFunction(). (игнорирование результата возврата - очень плохо)
  • int code = MyFunction(). result; (выбрасывая полезную нагрузку - может быть, все в порядке, если это предполагаемое использование.)
  • ФункцияResult x = MyFunction();//... (куча дополнительных объектов FunctionResult и дополнительный код для проверки их по всему месту)

Если вам нужно использовать коды возврата, это нормально. Но тогда используйте коды возврата. Не пытайтесь упаковать в него дополнительную полезную нагрузку. Для этого нужны параметры ref и out (С#). Необязательные типы могут быть исключением, но только потому, что для поддержки этого языка требуется дополнительный сахар, поддерживаемый им.

Если вы все еще не согласны с этой оценкой, DOWNVOTE этот ответ (не весь вопрос). Если вы думаете, что это анти-шаблон, то UPVOTE это. Мы будем использовать этот ответ, чтобы узнать, что думает сообщество.