Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

When applying the State Pattern illegal transitions should result in an exception being thrown (or at least that's what I understood from the pattern)

I know exceptions are for "unexpected behavior" where an action isn't supposed to happen. Errors would be more appropriate if the required action is common (ex: user enters a wrong password)

Now picture this, I have an admin panel where a list of orders are shown and each order has 3 buttons (Refund, Cancel, Reorder) where each one of them changes the state of the order if the operation is allowed.

The 3 buttons are enabled by default (I'm simplifying my case here as my real system is much more complex than that). Now a user can for example push the cancel button for an order with state (Cancelled) which is an invalid state transition.

  1. Since I expected that this illegal transition action to occur would a validation before attempting to Cancel the line be more appropriate?
  2. If I validate before transition do I still need exceptions in the model?
  3. Is there a better approach to the whole problem (ignoring disabling the buttons and client side validation)
share|improve this question
add comment

4 Answers

Client-side measures can never solve such a problem. Even if you disable smth and/or place validation, it is still possible to send invalid requests.

In this case I would disable the Cancel button in the UI. When the server receives a request to change state, I would validate it at server-side, ignore the request if the state is invalid and send an error status back to client. depending on the situation, I would also show an error message like The order has already been canceled.

share|improve this answer
add comment

It seems you can validate whether a transition is valid before attempting it. I think you should validate all possible transitions when showing the UI and disable the buttons that correspond to invalid transitions. Letting the user know what they can and can't do is a good thing.

Now, if you can't or don't want to do that, and so you expect invalid transitions to happen often, then I think you shouldn't use exceptions. Instead, you might want to use pattern similar to the various TryParse() methods in .Net, where the returned value indicates success or failure.

If you decide to have separate methods for validation and actually performing the transition (this is called Tester-Doer pattern), then you should still use exceptions if invalid transition is attempted, because you can't guarantee that the programmer that uses this code calls the Tester method. This pattern is also dangerous in multi-threaded environments, because the situation can actually change after the call to the Tester method, but before the call to the Doer method.

share|improve this answer
add comment

If you're in a client/server scenario, then the server should always update any requests (in this case, state transition requests) that it receives from the client.

Your server-side implementation needs to be robust enough to handle invalid requests without getting into an invalid state or corrupting data. There are various ways to handle this - e.g. the memento pattern.

Although the consequences of invalid transitions are less severe, your client-side implementation ought to prevent users from even trying invalid transitions. Disabling the buttons for invalid transitions is typical, or you might even want to remove them completely.

Showing an error message is the final fallback option when something goes wrong. In this case, that would be either the client/server state getting out of sync, or a bug in the client code where it thinks a transition is valid when it isn't.

As far as working out which transitions are valid on the client-side, you could just have each state hold a list of which states it can transition to.

share|improve this answer
add comment

Is there a better approach to the whole problem (ignoring disabling the buttons and client side validation)

Yes. The pattern is not being implemented correctly from what I'm reading.

Your "list of orders" screen should have it's own state-handling object.

This is a context class/object as seen in the state pattern class diagram.

The OrdersList sets its overall state based on user selections, button clicks, etc. Every user UI interaction triggers the OrdersList state object to validate - because after all the UI state just changed - and set internal booleans that tell us what states are OK now. Each specific boolean is wired into the UI via the context object, so selecting a (cancelled) order triggers context validation which knows cancel is not a valid next state and sets the "cancel boolean" to false. This boolean directly sets the Cancel button and voila.

States Do Not know how or if to allow other States

That's part of the point of the state pattern.

A given state knows how to validate itself. But how can it know what the next valid states are without some context? That context is the "list of orders" screen. Other screens in your app are also "context" of another kind. How in the world can every State object/class know about every button and user interaction possibility for the whole application? They cannot! Each context may have differing rules about what states are allowed. That's what the context class is about.

If I validate before transition do I still need exceptions in the model?

In the model / context object yes. In each State, no.

Since I expected that this illegal transition action to occur would a validation before attempting to Cancel the line be more appropriate?

The question is moot now that we see every screen as having it's own state. So: The user doing anything in the UI changes then we must validate its new state - that's the context object in action here. That context object validation sets UI controls so that only valid things are allowed.

A key is that all validation, all of it, is in your Model

The UI, client side, may have a modicum of validation but all logic necessary for determining state must be in your "behind the UI" model. Your context object looks at what's been clicked, selected, etc. and the context decides what to do.

If you're thinking that context might also be the Controller in the MVC pattern, I suspect you're right

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.