Ich habe oft die Notwendigkeit, ein Objekt zu implementieren, das in der Lage ist, sein Verhalten als Reaktion auf einen Benutzerbefehl zu wechseln. Dies könnte zum Beispiel der Fall sein, wenn ein Gerät der Klasse repräsentativ mit einem PC verbunden ist und vom Benutzer über eine GUI gesteuert wird. Allgemeiner muss das Gerät selbständig sein und eine eigene Ablaufplanung haben. Da ich dieses Verhalten aus der spezifischen Geräteklasse "extrahieren" möchte, um die Code-Wiederverwendung zu verbessern, schlage ich hier eine Templates endliche Zustandsmaschine Klasse mit Qt. Ich habe auch eine Beispielverwendung in Klasse A gemeldet. Was denkst du (erfahrenere Programmierer als ich) darüber? Ist es der "richtige" Weg, eine solche Klasse zu entwerfen? Gibt es Leistungsprobleme?Eine "verallgemeinerte" endliche Automatenimplementierung
template < class Base,
typename T,
class ThreadPolicy>
class FSM
{
public:
typedef bool (Base::*my_func)();
struct SState {
SState(){}
SState(const T& id_arg,
const T& next_arg,
const T& error_arg,
const QList<T>& branches_arg,
const my_func& op_arg) :
id(id_arg),
next(next_arg),
error(error_arg),
branches(branches_arg),
op(op_arg)
{}
T id; // state ID
T next; // next state
T error; // in case of error
QList<T> branches; // allowed state switching from current
my_func op; // operation associated with current state
};
typedef QMap<T ,SState> SMap;
bool switchState(const T& ns){
return _checkAllowed(ns);
}
bool addState(const T& id, const SState& s){
return _register(id, s);
}
protected:
void _loop(Base* ptr){
if ((ptr->*m_states[m_state].op)()) {
ThreadPolicy::Lock();
if(m_externalSwitch){
m_externalSwitch = false;
ThreadPolicy::Unlock();
return;
}
m_state = m_states[m_state].next;
ThreadPolicy::Unlock();
} else {
ThreadPolicy::Lock();
if(m_externalSwitch){
m_externalSwitch = false;
ThreadPolicy::Unlock();
return;
}
m_state = m_states[m_state].error;
ThreadPolicy::Unlock();
}
}
bool _checkAllowed(const T& cmd){
if (!m_states[m_state].branches.contains(cmd)) { return false;}
ThreadPolicy::Lock();
m_state = cmd;
m_externalSwitch = true;
ThreadPolicy::Unlock();
return true;
}
bool _register(const SState& s){
if(m_states.find(s.id) != m_states.end()) { return false; } // state with same ID already exist
m_states[s.id] = s; // add the new state to the map
return true;
}
SMap m_states; // map states to Baseclass methods
T m_state; // holds my current state
bool m_externalSwitch; // check if user request a state switch
};
class A :
public QObject,
public FSM< A, QString, MultiThreaded >
{
Q_OBJECT
A(){
// SState startState; myState.branches << "start" << "stop";
_register(SState("start",
"start",
"stop",QStringList(("start","stop")),
&A::_doStart));
_register(SState("stop",
"stop",
"stop",QStringList(("stop","start")),
&A::_doStop));
}
private slots:
void run(){
for(;;){
_loop(this);
QCoreApplication::processEvents();
}
}
private:
bool _doStart(){ return true;}
bool _doStop(){ return true;}
};
BTW die Frage, die Sie würde besser passen für SO-Code-Review-Website sind gefragt, wenn Sie wollen einfach nur wissen, ob Ihr Code gut ist oder nicht: http: // Codereview .stackexchange.com –