Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to persist objects which implement the State pattern?

I am new to the State design pattern and I can't find a proper example of saving different states of an object to the database (SQL Server in my case). The scenario is quite similar [almost identical] to the example described in the following article, however I have not found an applicable solution for persisting the states to the database. Can you guys recommend a link or possiblly give an example?

State Pattern Usage and Sample in C#

In addition: How do you enumerate all different ConcreteState types at run time? For instance, if you have 10 different states, do you declare an EnumStates with 10 different members and give every single ConcreteState member an associated EnumStates member, or you do get all the distinct states by getting the subclasses of ConcreteState?

For you information, I need to be able to search for entities based on their different states.

like image 375
MHOOS Avatar asked May 21 '14 10:05

MHOOS


People also ask

What is the purpose of encapsulating state in an object in the State pattern?

The state pattern is used in computer programming to encapsulate varying behavior for the same object, based on its internal state. This can be a cleaner way for an object to change its behavior at runtime without resorting to conditional statements and thus improve maintainability.

What is the applicability of State pattern?

Applicability. Use the State pattern in either of the following cases: An object's behavior depends on its state, and it must change its behavior at run-time depending on that state. Operations have large, multipart conditional statements that depend on the object's state.

How do you use state design patterns?

State design pattern is used when an Object changes its behavior based on its internal state. If we have to change behavior of an object based on its state, we can have a state variable in the Object and use if-else condition block to perform different actions based on the state.

When should a developer use the State pattern?

State design pattern is one of the behavioral design pattern. State design pattern is used when an Object change its behavior based on its internal state.


2 Answers

I didn't like the example you linked, below I listed the reasons:

  1. I agree that the persisting architecture will be a mess - way to messy in my opinion.
  2. Creating new instance per state seems to me like efficiency suicidal pattern.
  3. Testing will be hell... finding errors will be hell.. debugging will be hell.
  4. In over 30 years of experience I never seen this pattern being used even once in a data centric application - I did see it and used it in cases where I do not need to persist the information, in example when building a network layer - per port could be treated with that kind of state pattern.


I would go for this pattern instead:

pattern infrastructure

public interface IStateObject<T>
{
    T State { get; set; }
    void Process();
}

Example implementation for some pseudo Order object

public enum OrderState
{
    Taken,
    Approved,
    Payed,
    Emailed,
    BeforeShipment
    //etc.. etc..
 }

 public class Order : IStateObject<OrderStates>
 {
     //some linear fields of order..
     //: name, description, etc.. etc..

     public OrderStates State { get; set; }

     public void Process()
     {
         switch (State)
         {
             case OrderState.Taken:
                 // code to handle this state
                 break;
             case OrderState.Approved:
                 // etc..
                 break;
          }
         //persist myself to db.
     }
 }

It is very simple as you can save object per type per context of the object in one row.
Also an object is created once as intuitively it should have if we had no computer nears us..
But mostly because it is very straight forward and very flexible.

You might notice you actually may not need the IStateObject<T> at all - but I would argue you will need it later on when you want to process on vertical decisions. keep in mind that T doesn't have to be an enum. it could serve as common ground to evolve according to your app needs.

To further point out the mess I mentioned in the beginning of this answer,
Let's say we want to have history to previous states of the order:

Using the pattern offered in this answer - you add a PreviousOrderState property and now you have history per row.. And there are other ways I'm sure you can think of..

But using the "State Pattern" - you will be in serious problem... it will actually going to be complicated by a full "scale level" to do that.. you will have to be able to link from each type of table to each type of other table - or try to force Object Oriented on your database...

See my point? the States pattern is simply not designed for data centric apps.

Good Luck.

like image 156
G.Y Avatar answered Oct 21 '22 04:10

G.Y


Don't try to translate the states into columns in a table, that wont work.

Instead serialize the states using JSON.NET as it supports inheritance. Then store it in a table like:

create table OrderStates
(
    OrderId int not null,
    Data nvarchar(MAX) not null
);

Include more columns if you want but only columns which is required to identify what the states are used for.

To activate the inheritance support in JSON.NET you have to use:

var json = JsonConvert.SerializeObject(yourState, typeof(StateBaseClass), JsonConvert.DefaultSettings)`. 
using (var cmd = sqlConnection.CreateCommand())
{
    cmd.CommandText = "INSERT INTO OrderStates (OrderId, Data) VALUES(@OrderId, @Data)";
    cmd.Parameters.AddWithValue("OrderId", orderId);
    cmd.Parameters.AddWithValue("Data", json);
    cmd.ExecuteNonQuery();
}

Same goes when deserializing, specify the base class when using JsonConvert.DeserializeObject().

How do you enumerate all different ConcreteState types at run time? For instance, if you have 10 different states, do you declare an EnumStates with 10 different members and give every single ConcreteState member an associated EnumStates member, or you do get all the distinct states by getting the subclasses of ConcreteState?

Subclasses. It's the only way to be able to introduce new states or remove old ones without having to modify the other classes. Each modification of existing classes can introduce bugs.

like image 22
jgauffin Avatar answered Oct 21 '22 05:10

jgauffin