I have a state machine pattern implementation that's pretty straightforward, but I've got a design problem I don't know an elegant solution to.
Here's some partly pseudo code to illustrate.
class MainRoomState:State
public override void HandleJoinSuccess(string gameName, List<LobbyPlayer> players)
{
Context.CurrentState = new LobbyState(Context);
//the players list needs to be in the LobbyState
//that data is specific to the LobbyState
}
Basically, the event triggering the state change also is providing data that belongs in the new state, and I don't know if there's a nice way to do it besides a shared class in the parent Context object, or by mangling the constructor for this special case.
Edit - in more detail
I have my states setup to encapsulate state specific data as well as logic, which includes, in this case, a GUI screen belonging to the current state. This seems to be a more elegant way of handling not only separation of logic, but also state specific data.
Here's what my abstract state looks like,
public abstract class GameState
{
public GameState(Game context)
{
Context = context;
Net = context.Net;
}
//Incoming events
public abstract void HandleConnected();
public abstract void HandleDisconnected(string reason);
public abstract void HandleNetworkNotification(string msg);
public abstract void HandleGameStarting();
//there's about 20 more methods not shown here
Here's my Game class, mainly functioning as a data holder, but it also controls the game loop timer, firing main events, etc.
public class Game
{
public Game()
{
//...bunch of init code here
CurrentState = new DisconnectedState(this);
}
public GameState CurrentState
{
get;
set;
}
//more methods, etc
}
You'll see that I opted for composite containment of the CurrentState rather than implementing pass-through methods. That was mostly because I disliked the messiness of passing through the calls when I really didn't need to. Also, the whole state stores a reference to Context, rather than passing it per method.
I've got two questions/problems with the pattern.
- Every concrete state MUST implement in some fashion, EVERY method in the abstract State. This is ridiculous overkill, and currently most of my states only use 20-40% of the methods, leaving me with a couple pages of this:
public override void HandleGameStarting() { //not handled in this state }
- My second issue is that each state has it's own data that only needs to exist while in that state. I don't want to store a huge conglomeration of data in the Context object when a far more encapsulated way of handling it would be putting it in the state.
Looking over your example, I suppose one answer to my original question is that I could properly pass through the methods to the Current State, and just do a kind of hack with the data,
class Game
public override void HandleJoinSuccess(string gameName, List<LobbyPlayer> players)
{
CurrentState = new LobbyState(this);
CurrentState.HandleData(gameName,players);
//the players list needs to be in the LobbyState
//that data is specific to the LobbyState
}