Ho un'implementazione dello stato machine che è piuttosto semplice, ma ho un problema di progettazione a cui non conosco una soluzione elegante.
Ecco alcuni codici in parte pseudo per illustrare.
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
}
Fondamentalmente, l'evento che attiva la modifica dello stato fornisce anche dati che appartengono al nuovo stato, e non so se c'è un buon modo per farlo oltre a una classe condivisa nell'oggetto Contesto genitore, o maneggiando il costruttore per questo caso speciale.
Modifica - in modo più dettagliato
Ho il mio stato configurato per incapsulare i dati specifici dello stato e la logica, che include, in questo caso, una schermata della GUI che appartiene allo stato corrente. Questo sembra essere un modo più elegante di gestire non solo la separazione della logica, ma anche i dati specifici dello stato.
Ecco come appare il mio stato astratto,
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
Ecco la mia classe di gioco, che funziona principalmente come titolare di dati, ma controlla anche il timer del ciclo di gioco, gli eventi principali di attivazione, ecc.
public class Game
{
public Game()
{
//...bunch of init code here
CurrentState = new DisconnectedState(this);
}
public GameState CurrentState
{
get;
set;
}
//more methods, etc
}
Vedrai che ho optato per il contenimento composito di CurrentState anziché implementare i metodi pass-through. Ciò era dovuto principalmente al fatto che non mi piaceva il disordine nel passare le chiamate quando non avevo davvero bisogno di farlo. Inoltre, l'intero stato memorizza un riferimento a Context, piuttosto che passarlo per metodo.
Ho due domande / problemi con il modello.
- Ogni stato concreto DEVE implementare in qualche modo, OGNI metodo nello stato astratto. Questo è un ridicolo esagerato, e attualmente la maggior parte dei miei stati usa solo il 20-40% dei metodi, lasciandomi un paio di pagine di questo:
public override void HandleGameStarting() { //not handled in this state }
- Il mio secondo problema è che ogni stato ha i propri dati che devono solo esistere mentre si trovano in quello stato. Non voglio memorizzare un enorme conglomerato di dati nell'oggetto Contesto quando un modo molto più incapsulato di gestirlo sarebbe metterlo nello stato.
Osservando il tuo esempio, suppongo che una risposta alla mia domanda iniziale sia che potrei passare correttamente i metodi allo stato attuale e fare semplicemente una specie di modifica dei dati,
Gioco di classe
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
}