views:

48

answers:

1

I've recently returned to C++ development after a hiatus, and have a question regarding implementation of the State Design Pattern. I'm using the vanilla pattern, exactly as per the GoF book.

My problem is that the state machine itself is based on some hardware used as part of an embedded system - so the design is fixed and can't be changed. This results in a circular dependency between two of the states (in particular), and I'm trying to resolve this. Here's the simplified code (note that I tried to resolve this by using headers as usual but still had problems - I've omitted them in this code snippet):

#include <iostream>
#include <memory>

using namespace std;

class Context
{
public:
    friend class State;

    Context() { }

private:
    State* m_state;
};

class State
{
public:
    State() { }

    virtual void Trigger1() = 0;
    virtual void Trigger2() = 0;
};

class LLT : public State
{
public:
    LLT() { }
    void Trigger1() { new DH(); }
    void Trigger2() { new DL(); }
};


class ALL : public State
{       
public: 
    ALL() { }
    void Trigger1() { new LLT(); }
    void Trigger2() { new DH();  }
};  

// DL needs to 'know' about DH.
class DL  : public State
{           
public:
    DL() { }
    void Trigger1() { new ALL(); }
    void Trigger2() { new DH();  }
};      

class HLT :  public State
{
public:
    HLT() { }
    void Trigger1() { new DH(); }
    void Trigger2() { new DL(); }
};

class AHL : public State
{
public:
    AHL() { }
    void Trigger1() { new DH();  }
    void Trigger2() { new HLT(); }
};

// DH needs to 'know' about DL.
class DH  : public State
{
public:
    DH () { }
    void Trigger1() { new AHL(); }
    void Trigger2() { new DL();  }
};


int main()
{
    auto_ptr<LLT> llt (new LLT);
    auto_ptr<ALL> all (new ALL);
    auto_ptr<DL>  dl (new DL);
    auto_ptr<HLT> hlt (new HLT);
    auto_ptr<AHL> ahl (new AHL);
    auto_ptr<DH>  dh (new DH);  

    return 0;
}

The problem is basically that in the State Pattern, state transitions are made by invoking the the ChangeState method in the Context class, which invokes the constructor of the next state.

Because of the circular dependency, I can't invoke the constructor because it's not possible to pre-define both of the constructors of the 'problem' states.

I had a look at this article, and the template method which seemed to be the ideal solution - but it doesn't compile and my knowledge of templates is a rather limited...

The other idea I had is to try and introduce a Helper class to the subclassed states, via multiple inheritance, to see if it's possible to specify the base class's constructor and have a reference to the state subclasse's constructor. But I think that was rather ambitious...

Finally, would a direct implmentation of the Factory Method Design Pattern be the best way to resolve the entire problem?

+4  A: 

You can define the member functions outside of the class definitions, e.g.,

class DL : public State
{
public:
    void Trigger2();
};

inline void DL::Trigger2() { new DH(); }

Define the member functions that rely on later class definitions after those classes are defined. The inline keyword is only necessary if you define the member function outside of the class in the header file.

As an aside, why are you just using new DH() in your functions; you're leaking memory everywhere!

James McNellis
Hi James! Many, many thanks indeed for the fast answer - that works perfectly :-) Apologies, I forgot to put the corresponding deletes in for each of the new() calls in the code snippet.
HypersonicNinja
@hyper: No problem; I just wanted to make sure that wasn't the _only_ thing in your functions... :-)
James McNellis