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.

In the following image for the State Pattern from Applying Domain-Driven Design and Patterns: With Examples in C# and .NET

enter image description here

I'm trying to persist the SalesOrder entity into the database. Normally I would have a salesOrder table in my database with a field currentState pointing to the current state of the entity.

This implementation is fine as there is a single entity and its states only contain different behavior.

However, what if I had to track other properties for the different states? Examples:

  • When a SalesOrder is cancelled I need to track the cancelled quantity,cancellationReason, cancelledBy, cancellationDate.
  • When a SalesOrder is Refunded I need to track refundQuantity, refundPrice, refundFee.

So basically it is like I have a CancelledSalesOrder and RefundedSalesOrder entities with additional attributes. Same can be said for the other states as well.

So my problem now is that I will have to change the design from using the state pattern into using inheritance. However, inheritance doesn't allow my to dynamically change my state at run time (the problem which the state diagram solves initially).

so my questions:

  1. Does the state pattern fail when an entity in each state has additional attributes? what's the alternative?
  2. How should I persist my entities in this case? Single table inheritance? table per class? table per concrete class?
  3. If I have to maintain some attributes from a former state (Refund a Shipped order, but don't delete the Shipping address from Shipped state ), how would one approach this problem?
  4. How do you keep track of the order of which the states occurred?
share|improve this question

1 Answer 1

up vote 2 down vote accepted

No, the state pattern does not fail. Just make the additional "cancel" attributes part of the "Cancelled" state, and the additional "refunded" attributes part of the "Refunded" state ( you just forgot the latter state in your diagram, I guess?)

Since any "state" entity is an aggregate of the SalesOrder, any attributes of "state" can be seen just an "addition of details" to the SalesOrder.

Which kind of inheritance mapping you choose for your OrderState hierarchy actually does not matter for your problem, any of the typical three will work .

The state pattern also allows you to keep attributes of a former state even when the state changes afterwards. For example, you might need to keep the "shipping address" even when the state changes from "Shipped" to "Invoiced". This can be solved by allowing multiple states at once, just make the relationship between SalesOrder and OrderState "1:n" instead of "1:1". So you don't "change the state from shipped to invoiced" but add the additional state "invoiced" to an entity "StateOrder", without removing the state "invoiced" beforehand. Of course, using this model, when looking for all orders to be shipped, you must check not only for orders which are "granted", but for "orders which are granted but not already shipped". But that's only a detail in the processing which should not be too hard to handle.

Having multiple states is IMHO the "better" model, since it reflects the real world situation more adequate. For example, something you have shipped and invoiced is "shipped and invoiced", not "invoiced instead of shipped".

share|improve this answer
    
You last paragraph is actually one of the things I forgot to mention in my question. gonna edit it to add it. –  Songo Jan 22 at 12:19
    
Well I what about the order of the states? I thought about adding a table for each state, but not all states have additional attributes. Single table inheritance isn't a good option because I need to avoid altering tables if a new state is added. In addition I still need to keep track of the order of the states. How do I accomplish that?\ –  Songo Jan 22 at 13:03
    
@Songo: If you want to use "one table per state", your favorite OR mapper will know how to deal with tables without attributes (there is actually no difference between single or multiple states per SalesOrder). If you want to implement the OR mapping by yourself, have a look how other ORM tools solve that problem (for example: docs.jboss.org/hibernate/orm/3.3/reference/en/html/…) –  Doc Brown Jan 22 at 14:35
1  
@Songo: keeping track of the order of which the states occurred is pretty simple: give the "OrderState" an additional time stamp attribute. –  Doc Brown Jan 22 at 14:39

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.