views:

1440

answers:

3

The software I will be building will involve "application" switching between different status a lot. Certain tasks can be done depends on the status an application is at. I was thinking about using enum as the status

public class Application
{
  public int Id {get;set;}
  public Status {get;set;}
}
public enum Status
{
  [Description("New")]New = 1, [Description("Closed")]Closed = 2
}

But then I thought maybe it’s good to use lookup table in the database as status does get updated/re-ordered quite often

table status (id int pk, desc string, sort_order int)
table application (id int pk, status_id int fk)

In my case I need to do things like

if (application.Status == Status.New)
{ //do something }
else if (application.Status == Status.Closed)
{ //do other things }

I think the above case is easier to do with enum. However when it comes to updating status sort order or description it'll be quite hard.

Should I used reflection to dynamically create enum based on values from lookup table? Or should I use state pattern? The problem I see with enum relfection is performance impact. And state pattern can produce a lot of redundant code.

What do you think? Thanks in advance!

+1  A: 

I'd create a Status class that contains the differences, and call those. So (in Python):

class StatusZero(object):
    def call_me(self, app):
       print 'Hello, from ' + app.name
       return db.prepare_specific_status_zero_request()


class StatusOne(object):
    def call_me(self, app):
        print 'Hi, from ' + app.name
        return db.prepare_specific_status_one_request()

states = { 'status_zero' : StatusZero(), 'status_one' : StatusOne() }

class Application(object):
    name = 'My App'
    status = states['status_zero']

    def change_state(self, state):
        status = state

    def call_me(self):
        state_key = self.status.call_me(self)
        self.change_state(states[state_key])

Fast, easy to keep the functionality compartmentalized, and with a reasonable inheritance pattern between the states you can share the functions which don't differ.

Chris B.
how do u handle the retrieving from db and cast to object bit without if else statement as i mentioned in answer 3?
Jeffrey C
I guess I have a hard time understanding the issue. Each of the Status objects can contain any code you want--including hard-wired casts if that's necessary. The Application object can remain the same; it dispatches the calls which differ to the internal Status.
Chris B.
my issues is how to avoid hand written if else statement when cast data table back to the object in correct state,in your example, how do you cast data row back to StatusZero or StatusOne without if else statment?
Jeffrey C
Oh, you mean to drive the state of the application from the results of the database call? Ideally, the "next state" would be stored in the database as an int, and you can use that to lookup the index in the state array. But a string works just as well in a hash lookup. I'll edit the example.
Chris B.
+3  A: 

You should not sprinkle your code with this check everywhere

if (application.Status == Status.New)
{ //do something }
else if (application.Status == Status.Closed)
{ //do other things }

Instead, use the state pattern. Change the state whenever the mode of the application changes and forward all your calls to the state's methods. You'll have a much cleaner and easier to maintain code.

As for changing the status, that has got nothing do with the state pattern. So you can use whichever approach is elegant.

Frederick
A: 

my understanding is that state pattern is quite good for UI only or in memory only executions, where in my situation when retrieving data back from application table, there still need to be if else statement to determine what object to cast to.

public AbstractApplication convert_db_application_to_object(obj db_application)
{
   AbstractApplication app;
   if (db_application.Status == (int)Status.New)
      app = application_factory.create(application_state_new);
   else if(db_application.Status == (int)Status.Closed)
      app = application_factory.create(application_state_closed);

   return app;
}

i don't see this as an elegant solution as i still need either an enum or lookup table to save the application status into database

Jeffrey C