2011年2月5日 星期六

State Patterns in Practice (C++)

Recently I posted a workflow here. I want to express the workflow in terms of state patterns. There are only two steps. Step 1: Prepare the framework.

// state/state.h
#ifndef STATE_STATE_H_
#define STATE_STATE_H_
#pragma once

namespace state {

class State {
public:
virtual ~State() {}

virtual void update() = 0;
virtual void draw() const = 0;
virtual void onEnter() {}
virtual void onLeave() {}
};

} // namespace state

#endif // STATE_STATE_H_

// state/state_factory.h
#ifndef STATE_STATE_FACTORY_H_
#define STATE_STATE_FACTORY_H_
#pragma once

#include <string>

namespace state {

class State;

class StateFactory {
public:
virtual ~StateFactory() {}
virtual State* createState(const std::string& name) = 0;
};

} // namespace state

#endif // STATE_STATE_FACTORY_H_

// state/state_manager.h
#ifndef STATE_STATE_MANAGER_H_
#define STATE_STATE_MANAGER_H_
#pragma once

namespace state {

class State;

class StateManager {
public:
StateManager();
virtual ~StateManager() {}

inline State* current_state() { return current_state_; }
virtual void switchToState(State* state);

private:
State* current_state_;
};

} // namespace state

#endif // STATE_STATE_MANAGER_H_

// state/state_manager.cc
#include "state_manager.h"
#include "state.h"
#include "base/basictypes.h"

namespace state {

StateManager::StateManager()
: current_state_(NULL) {
}

void StateManager::switchToState(State* state) {
if (!!current_state_) {
current_state_->onLeave();
}

if (!!state) {
current_state_ = state;
current_state_->onEnter();
}
}

} // namespace state


Step 2: Combine them. I will not post all details but post important files instead.
// app_state_factory.h (not completed)
#include "state/state_factory.h"

class AppController;

class AppStateFactory : public state::StateFactory {
public:
explicit AppStateFactory(AppController* controller);
virtual state::State* createState(const std::string& name);

private:
AppController* controller_;
};

// app_controller.h
namespace state {
class State;
}

class AppStateManager;
class AppStateFactory;

class AppController {
public:
AppController();
~AppController();

void init();
void deinit();

void update();
void draw() const;

void switchToState(const std::string& name);

private:
void initAllStates();

private:
AppStateManager* state_manager_;
AppStateFactory* state_factory_;
std::map<std::string, state::State*> states_;
};

// app_state_manager.h
#include "state/state_manager.h"

class AppStateManager : public state::StateManager {
public:
AppStateManager();
virtual ~AppStateManager();
};

// state/initial_state.h
#include "state/state.h"

class AppController;

class InitialState : public state::State {
public:
explicit InitialState(AppController* controller);
virtual ~InitialState();

virtual void update();
virtual void draw() const;
virtual void onEnter();
virtual void onLeave();

private:
AppController* controller_;
};

// state/initial_state.cc
#include "initial_state.h"
#include "../app_controller.h"

InitialState::InitialState(AppController* controller)
: controller_(controller) {
}

InitialState::~InitialState() {
}

void InitialState::update() {
}

void InitialState::draw() const {
}

void InitialState::onEnter() {
// TODO: Load necessary resources.
if (!!controller_) {
controller_->switchToState("idle");
}
}

void InitialState::onLeave() {
}

Keep working!

沒有留言:

張貼留言