Исключение против специального типа.Что может упасть? - PullRequest
3 голосов
/ 05 октября 2011

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

В книге предлагается создать специальный класс в доменной модели и вернуть его. Э.Г.

public sealed class MissingCustomer: Customer
{

}

// On method failure return new MissingCustomer();

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

Что вы думаете об этом подходе и сталкивались ли вы со сценарием, в котором это имело существенное значение?

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

В любом случае я думаю, что нам понадобится класс MissingCustomer или MissingCustomerException, так как клиент - это очень распространенная сущность, которая используется во всей системе. Если модель представления ожидает клиента, а мы возвращаем MissingCustomer - это нормально, так как наследование заставит это работать.

Например, у меня есть метод действия, который возвращает OrderViewModel. Этот метод действия требует ссылки на клиента.

Customer customer = CustomerRepository.Find(10);
if(customer == null)
{
    return new MissingCustomer();
}

Это упадет, потому что метод действия вернет модель представления типа OrderViewModel, поэтому теперь я больше склонен к использованию исключения вместо объекта MissingCustomer.

Редактировать

Кроме того, объект типа MissingCustomer будет наследовать свойства от типа Customer. Эти свойства не нужны, так как единственное, что мы хотим сделать, это уведомить пользователей о том, что клиент не может быть найден.

Спасибо

Ответы [ 5 ]

2 голосов
/ 05 октября 2011

Я бы всегда возвращал null из методов, используемых для получения клиентов. Просто взглянув на функцию с именем GetCustomer, никто бы не ожидал, что она может вернуть объект customer, который на самом деле не является клиентом.

Гораздо лучше, если вы можете использовать что-то вроде var customer = repos.GetCustomer(1) ?? Customer.Empty. Цель ясна, и код становится менее подверженным ошибкам.

Если ваш метод ожидает всегда получить клиента, вы не смогли подтвердить ввод ранее. Вместо того, чтобы создавать обходной путь, чтобы заставить код работать, попробуйте исправить это раньше. Может быть, проверить, существует ли клиент?

Обновление

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

Я бы использовал

public class YourViewModel
{
    public Customer Customer { get { return _customer ?? Customer.Empty; }}
}
2 голосов
/ 05 октября 2011

Это похоже на шаблон Null Object , который полезен, если у вас есть некоторый код, который принимает объект Customer, и вам нужен этот код, чтобы он мог запускаться и не выдавать ошибку, даже еслиу вас нет объекта Customer для его выдачи.

Например, скажем, у вас есть представление, в котором отображаются детали Заказа, и возможно, что в некоторых случаях Заказу присвоено значение Customer, равное нулю.,Вы не хотите отображать сообщение об ошибке в этом случае, вы все равно хотите отобразить детали заказа и, возможно, «Нет» для клиента.

У вас есть два варианта: либо кодировать представление, чтобыв частности, проверьте нулевого клиента и выведите «None», либо заполните Order с помощью специального объекта MissingCustomer, имя которого «None», и забудьте о проверках NULL.

В зависимости от ситуации вы можете обнаружить, чтоэтот шаблон сохраняет большую часть кода "if null".

С другой стороны, если вы намерены использовать класс MissingCustomer для проверки ошибок, в этих строках ...

Customer c = ...
if (c is MissingCustomer)
{
    // Display error, no customer found
}

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

В моеммнение:

  • Если это метод, который вы обычно ожидаете вернуть объект, то невозможность создания объекта является ошибкой и должна указываться как таковая (за исключением).Если ошибка должна быть обработана в некоторых случаях, используйте пользовательский класс исключений и перехватывайте исключение в этих случаях.
  • Если вы ожидаете, что это метод, который, как вы ожидаете, может возвращать или не возвращать объект, используйте нуль в качестве "нет записи "результат и исключения для других ошибок.Метод может быть назван так, чтобы напомнить вам, что можно вернуть значение null, например «TryGetCustomer», или даже просто соглашение о том, что методы «Find» хранилища могут возвращать null.
  • Если у вас есть код, которыйвыполняет множество проверок «если ноль», вы можете рассмотреть шаблон «Нулевой объект / особый случай», чтобы потенциально упростить этот код.
1 голос
/ 06 октября 2011

Это вопрос ответственности, но возвращение нулевого объекта подразумевает, что слои вверх по стеку вызовов будут знать, что с ним делать.

  • Возвращение объекта типа MissingCustomer также подразумевает, что выделать соответствующую регистрацию ошибок внутри / под созданием MissingCustomer.Если это не так, вам нужно разрешить всплывающим данным об исключении (лучше всего вернуть исключение - при условии, что оно исключительное).

Например, у меня есть метод действия, который возвращает OrderViewModel,Этот метод действия требует ссылки на клиента.

Вы всегда можете использовать подход сегрегации: вместо того, чтобы связать представление с клиентом, соедините его с представлением требуемых данных ("CustomerOrderSummary"объект / интерфейс, например).Это соответствует принципу интерфейса сегрегации , а также соответствует частям MVVM: где вы приспосабливаете данные, которые обмениваются к сценарию использования.

1 голос
/ 05 октября 2011

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

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

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

В MVC я считаю, что полезно думать о вещах в терминах адресуемых ресурсов.

Если ваш пользователь переходит к ресурсу / YourApp / Customer / 22 и существует клиент Customer 22, то вы можете выполнить одно из следующих действий:

  • Направить их на общую страницу 404 (ресурс не найден).
  • Дайте им индивидуальный ответ, например: «Извините, клиент не найден».

Подумайте, как вы хотите сообщить, чтоситуация для ваших пользователей.

Подход, предложенный в книге, неплохой, но я бы, вероятно, реализовал ту же идею в духе свойства String.Empty, добавив статическое поле только для чтения вобъект Customer сам по себе ...

static readonly Customer Missing = new Customer();
1 голос
/ 05 октября 2011

У меня сейчас точно такая же проблема, и я собираюсь использовать подход типа ad-hoc.

Причина, по которой я выбираю этот подход, состоит в том, что я хочу отобразить свой экземпляр «customer» как «Имя клиента» не может быть найдено ». В моем решении важно, чтобы другие задачи выполнялись нормально. Тот факт, что этот конкретный экземпляр Customer не был найден, не является проблемой остановки.

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

Вот что я сделаю в любом случае.

...