jeudi 19 novembre 2015

In what situation should we adopt state pattern?

In what situation should we adopt state pattern?

I've been assigned to maintain a project, the project state machine was implemented by switch-case that are 2000+ lines long. It will be hard to expand function, so I would like to refactor it. I'm surveying state design pattern, but I have some confusions.

A simple example:

1. Initial state "WAIT", wait user send download command

2. While user send download command, move to "CONNECT" state, connect to server

3. After connection is created, move to "DOWNLOADING" state, keep receive data from server

4. While the data download complete, move to "DISCONNECT", disconnect link with server

5. After disconnect, move to "WAIT" state, wait user send download command

A simple state machine pic

  • Method 1: Before I survey state pattern, I think a trivial method --- wrapper different state behavior in different function, use a function pointer array to point each state function, and change state by call function.

    typedef enum {
        WAIT,
        CONNECT,
        DOWNLOADING,
        DISCONNECT
    }state;
    void (*statefunction[MAX_STATE])(void) = 
    {
        WAITState,
        CONNECTState,
        DOWNLOADINGState,
        DISCONNECTState
    };
    void WAITState(void)
    {
        //do wait behavior
        //while receive download command
        //statefunction[CONNECT]();
    }
    void CONNECTState(void)
    {
        //do connect behavior
        //while connect complete
        //statefunction[DOWNLOADING]();
    }
    void DOWNLOADINGState(void)
    {
        //do downloading behavior
        //while download complete
        //statefunction[DISCONNECT]();
    }
    void DISCONNECTState(void)
    {
        //do disconnect behavior
        //while disconnect complete
        //statefunction[WAIT]();
    }
    
    
  • Method 2: The state pattern encapsulates different state and its behavior in different class (object-oriented state machine), uses polymorphism to implement different state behavior, and defines a common interface for all concrete states.

    class State
    {
    public:
         virtual void Handle(Context *pContext) = 0;
    };
    class Context
    {
    public:
        Context(State *pState) : m_pState(pState){}
    
        void Request()
        {
            if (m_pState)
            {             
                m_pState->Handle(this);           
            }
         }   
    private:
        State *m_pState;
    };
    class WAIT : public State
    {
    public:
        virtual void Handle(Context *pContext)
        {
            //do wait behavior
        }
    };
    class CONNECT : public State
    {
    public:
        virtual void Handle(Context *pContext)
        {
            //do connect behavior
        }
    };
    class DOWNLOADING : public State
    {
    public:
        virtual void Handle(Context *pContext)
        {
            //do downloading behavior
        }
    };
    class DISCONNECT : public State
    {
    public:
        virtual void Handle(Context *pContext)
        {
            //do disconnect behavior
        }
    };
    
    

I'm wondering whether the state pattern batter than function pointer in this case or not... Using function pointer only also can improve readability (compare with switch-case), and more simple. The state pattern will create several class, and more complex than using function pointer only. What's the advantage of using state pattern?

Thanks for your time!

Aucun commentaire:

Enregistrer un commentaire