Boost logo

Boost Users :

From: Dave (pplppp_at_[hidden])
Date: 2005-07-18 16:12:35


> > All this is fine if PumpBase has few states. Yet consider the case when 2
> > developers work on PumpBase, one responsible for customizing the Running
> state,
> > the other for customizing the Stopped state. The developers should be able to
> > work on the state machine without knowing each other. Yet as I've illustrated
> > above, there can only be one MyPump class and whoever writes that class has
> to
> > be aware of the MyRunning and MyStopped class and write the react functions
> > accordingly.
>
> I'm not sure whether I understand 100% but it seems if you use the
> technique above this shouldn't be a problem.

I followed your example/suggestions and wrote the following test program.
Conceptually speaking, the PumpBase FSM has 2 states, Idle and Running, the
designer of this FSM want to allow customization of these 2 states, which is
limited to adding inner states. The customization for the Idle state (MyIdle)
could be developed by Bob, while the customization for the Running state
(MyRunning) could be developed by Mary and since Bob and Mary are adding inner
states to Idle and Running respectively, their code should not depend on each
other. However, as my test program shows, MyPump class needs to have knowledge
of both MyIdle and MyRunning and provide the implementation for the react
functions.

This means the 2 points of customization cannot be viewed as separate and
independent. If MyPump only customized the Idle state but not the Running state,
and a third developer with no access to MyPump's source code will have to
customize MyPump to add inner states for the Running state.

PumpBase
 +--> MyPump
       +--> CustomMyPump

I don't mean to say that this will prevent anything from working but I just want
to clarify what I was trying to point out. Please correct me if I'm wrong

thanks

Dave

struct EvStart : sc::event< EvStart > {};
struct EvPreIdleStart : sc::event< EvPreIdleStart > {};
struct EvPreRunningStart : sc::event< EvPreRunningStart > {};

class EntryExitDisplayer { ... }

////////////////////////////////////////////////////////////////////////////////
// Base FSM
////////////////////////////////////////////////////////////////////////////////

struct PreIdle;
struct PreRunning;
struct PumpBase : sc::state_machine< PumpBase, PreIdle >
{
    virtual sc::result react(PreIdle & preIdle, const EvPreIdleStart & ) const;
    virtual sc::result react(PreRunning & preRunning, const EvPreRunningStart &
) const;
};

struct PreIdle : sc::state<PreIdle, PumpBase>, EntryExitDisplayer
{
    typedef sc::custom_reaction< EvPreIdleStart > reactions;

    PreIdle(my_context ctx) : my_base(ctx), EntryExitDisplayer("PreIdle")
    {
        post_event( boost::intrusive_ptr<EvPreIdleStart>(
            new EvPreIdleStart() ) );
    }

    sc::result react( const EvPreIdleStart & evt )
    {
        return context< PumpBase >().react( *this, evt );
    }
};

struct Idle : sc::simple_state< Idle, PumpBase>, EntryExitDisplayer
{
    typedef sc::transition< EvStart, PreRunning > reactions;

    Idle() : EntryExitDisplayer("Idle") {}
};

struct PreRunning : sc::state<PreRunning, PumpBase>, EntryExitDisplayer
{
    typedef sc::custom_reaction< EvPreRunningStart > reactions;

    PreRunning(my_context ctx) : my_base(ctx), EntryExitDisplayer("PreRunning")
    {
        post_event( boost::intrusive_ptr<EvPreRunningStart>(
            new EvPreRunningStart() ) );
    }

    sc::result react( const EvPreRunningStart & evt )
    {
        return context< PumpBase >().react( *this, evt );
    }
};

struct Running : sc::simple_state< Running, PumpBase >, EntryExitDisplayer
{
    Running() : EntryExitDisplayer("Running") {}
};

sc::result PumpBase::react(PreIdle & preIdle, const EvPreIdleStart & ) const
{
    return preIdle.transit< Idle >();
}

sc::result PumpBase::react(PreRunning & preRunning, const EvPreRunningStart & )
const
{
    return preRunning.transit< Running >();
}

///////////////////////////////////////////////////////////////////////////////
// Custom FSM
///////////////////////////////////////////////////////////////////////////////

struct MyIdle : sc::simple_state< MyIdle, PumpBase >, EntryExitDisplayer
{
    typedef sc::transition< EvStart, PreRunning > reactions;

    MyIdle() : EntryExitDisplayer("MyIdle") {}
};

struct MyRunning : sc::simple_state< MyRunning, PumpBase >, EntryExitDisplayer
{
    MyRunning() : EntryExitDisplayer("MyRunning") {}
};

struct MyPump : PumpBase
{
    virtual sc::result react( PreIdle & preIdle, const EvPreIdleStart & ) const
    {
        return preIdle.transit< MyIdle >();
    }

    virtual sc::result react( PreRunning & preRunning, const EvPreRunningStart &
) const
    {
        return preRunning.transit< MyRunning >();
    }
};

int main(int argc, char** argv)
{
    MyPump p;
    p.initiate();
    std::cout << "External event EvStart posted...\n";
    p.process_event(EvStart());
    sleep(5);
    return 0;
}


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net