Exception vs ad-hoc type. What is likely to fall over?

孤人 提交于 2019-12-05 02:55:42

问题


I'm reading a book development of enterprise applications while working on MVC 3 project. I'm currently deciding on how to handle exceptions. Previously I would let the exception bubble up the stack and then handle it at the highest layer.

The book suggests to create an ad-hoc class in a domain model and return that. E.g.

public sealed class MissingCustomer: Customer
{

}

// On method failure return new MissingCustomer();

I can see the idea but I'm struggling to justify a need for that. Code wise I agree that it's a lot neater to return a new missing customer, instead of throwing an exception.

What do you think about this approach and have you come across scenario where this made a significant difference?

If we assume that a customer must always exist, then it makes sense to throw an exception saying "Hey, customer should always exist and for some reason it doesn't, so I'm going to notify user saying that something exceptional happened". On other hand I can assume that it's possible for a customer to be removed by another person, therefore I need to handle this gracefully.

Either way I think that we'll need a MissingCustomer class or a MissingCustomerException as customer is a very common entity which is used throughout the system. If the view model expects a customer and we return a MissingCustomer - it's fine as inheritance will get this working.

For example I have an action method that returns OrderViewModel. This action method requires a reference to a customer.

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

This is going to fall over because action method will return a view model of type OrderViewModel, so now I'm more inclined towards using an exception, instead of a MissingCustomer object.

Edit

Additionally, a MissingCustomer type object would inherit properties from Customer type. These properties are not needed as the only thing we want to do, is notify users that customer can't be found.

Thank you


回答1:


I would always return null from methods used to fetch customers. By just looking at a function named GetCustomer one would never expect that it can return a customer object which is not really a customer.

It's far better that you use something like var customer = repos.GetCustomer(1) ?? Customer.Empty if you can. The intent is clear and the code becomes less error prone.

If your method expects to always get a customer you have failed to validate the input earlier on. Instead of creating a workaround to get the code working, try to fix it earlier on. Maybe a check to see if the customer exists?

Update

I noticed now that the question really was for your view model. It's perfectly fine to use that kind of logic in it. The view model after all used to adapt the "M" in MVC to suit the view (and therefore remove logic from the view).

I would use

public class YourViewModel
{
    public Customer Customer { get { return _customer ?? Customer.Empty; }}
}



回答2:


This sounds similar to the Null Object pattern, which is useful if you have some code that takes in a Customer object, and you need that code to be able to run and not throw an error even if you don't have a Customer object to give it.

For example, say you have a view that displays the details of an Order, and it is possible that in some cases the Order has its Customer set to null. You don't want to display an error message in this case, you want to still display the details of the order, and maybe "None" for the customer.

You have two choices: Either code the view to specifically check for a null customer and output "None", or fill in the Order with a special MissingCustomer object whose name is "None" and forget about the null checks.

Depending on the situation, you might find that this pattern saves a lot of "if null" code.

On the other hand, if you intend on using the MissingCustomer class for error checking, along these lines...

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

...that is just throwing out a perfectly good error handling mechanism (exceptions) and using something much more bug-prone. You'll have to remember to check for MissingCustomer all the time, and in the places you forget, you'll probably get some hard-to-detect and hard-to-debug incorrect program behaviour.

In my opinion:

  • If it's a method that you would normally expect to return an object, not being able to produce an object is an error, and should be indicated as such (with an exception). If the error should be handled in some cases, use a custom exception class and catch the exception in those cases.
  • If it's a method that you would expect may or may not return an object, use null as the "no record" result, and exceptions for other errors. The method might be named in a way that reminds you that null can be returned, such as "TryGetCustomer", or even just a convention that repository "Find" methods can return null.
  • If you have some code that is doing lots of "if null" checks, you could consider the Null Object / Special Case pattern to potentially simplify that code.



回答3:


I am having the exact same issue right now and I am going to use the ad-hoc type approach.

The reason why I am choosing that approach is because I want to display my instance of "customer" as "The customer 'Name' could not be found". In my solution, it is important that other tasks execute normally. The fact that this particular instance of Customer wasn't found isn't a stopping problem.

So, if you have some behavior for the case where the Customer is missing, use the ad-hoc. If you cannot continue without the customer, throw exception.

That's what I will do anyway.




回答4:


It depends... Exceptions should only be thrown in exceptional cases, e.g. when you really have no way of knowing what's going on or how it should be handled.

If you had a concrete idea for how you would handle this particular exception in your top layer, then I would say you shouldn't be using exceptions.

Suppose your program allows the user to search for a customer by name, and that customer cannot be found: that's not an exception, it's part of something that your application should be built to deal with.

In MVC, I find that it's useful to think of things in terms of being addressable resources.

If your user navigates to the resource /YourApp/Customer/22, and Customer 22 doen's exist, then you could do one of the following:

  • Route them to a generic 404 page (Resource Not Found).
  • Give them a tailored reponse, e.g. "Sorry, customer not found".

Think about how you want to communicate that situation to your users.

The approach suggested in the book isn't a bad one, but I'd probably implement the same idea along the lines of of String.Empty property, by adding a static readonly field to the Customer object itself...

static readonly Customer Missing = new Customer();



回答5:


It's a question of responsibilities, but returning a null object does imply that the layers up the call stack will know what do do with it.

  • Returning a MissingCustomer type object also implies you're doing appropriate error logging within / underneath the creation of the MissingCustomer. If you aren't then you need to let the exception data bubble up (returning an exception would be best - assuming it's execeptional).

For example I have an action method that returns OrderViewModel. This action method requires a reference to a customer.

You could always take a segregation type of approach: rather than couple the view to a customer, couple it to a representation of the required data ("CustomerOrderSummary" object / interface, for example). This is along the lines of the Interface Segregation Principle, and is also in keeping with parts of MVVM: where you tailor the data that is exchanged to the scenario of use.



来源:https://stackoverflow.com/questions/7658527/exception-vs-ad-hoc-type-what-is-likely-to-fall-over

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!