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

StackOverflow https://stackoverflow.com/questions/72682

  •  09-06-2019
  •  | 
  •  

Вопрос

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

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

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

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

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

    return result;
}

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

Это было полезно?

Решение

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

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

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

Другие советы

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

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

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

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

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

вместо того, чтобы

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

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

Но это является все еще немного странно - поскольку это похоже на C #, тогда он должен использовать параметр out .Весь прирост эффективности, вероятно, будет потерян при создании экземпляра класса.

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

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

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

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

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

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

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

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

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

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

bool TryMyFunction(out FunctionResult result){    

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

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

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

  1. Объект x = myFunction().полезная нагрузка; (игнорирование возвращаемого результата - очень плохо)
  2. int code = myFunction().результат; (выбрасывание полезной нагрузки - может быть, и нормально, если это используется по назначению.)
  3. FunctionResult x = myFunction();//... (куча дополнительных объектов FunctionResult и дополнительный код для проверки их повсюду)

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

Если вы все еще не согласны с этой оценкой, ОПУСТИТЕ этот ответ (не весь вопрос).Если вы действительно считаете, что это антишаблон, тогда ПОДДЕРЖИТЕ его.Мы воспользуемся этим ответом, чтобы узнать, что думает сообщество.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top