I have an Order class which goes through a series of defined states. To aid with this, I have implemented the State pattern such that the Order object has a CurrentState member which implements an IOrderState interface. I then have concrete implementations of this interface such as OrderStateNew, OrderStateDelivered etc etc
My question is, what is the correct way to transition the Order object between states? Is it acceptable to have an Order.SetState() method which allows an external service to set the state? The criteria which determine the state changes are stored externally to the Order object so this seems the obvious answer but I'm slightly uneasy about having a public method on my object to change something as fundamental as this.
Additional clarification I thought it might be useful to add some more detail about my implementation because I wonder if I'm actually using the pattern correctly in the first place. Here's the pulbic API for creating and authorising an order
Dim orderFacade As New OrderFacade
Dim order = orderFacade.createFrom(customer)
' Add lines etc
' This will validate the order and transition it to status 'Authorised'
Dim valid = orderFacade.Authorise(order)
' This will commit the order, but only if it is at status 'Authorised'
Dim result = orderFacade.Commit()
The OrderFacade.Authorise() function looks something like this
Public Function Authorise(ByRef originalOrder As Order) As ValidationSummary
If originalOrder.CurrentState.CanAuthorise() Then
Dim validator = OrderValidatorFactory.createFrom(originalOrder)
Dim valid = validator.ValidateOrder(originalOrder)
If valid.IsValid Then
originalOrder.SetOrderStatus(OrderStatus.Authorised)
End If
Return valid
End If
End Function
As you can see, the CurrentState member is the current IOrderState implementation which determines which activities are valid for the object. I wonder whether this should be responsible for determining the transition rather than the OrderFacade?