2

I am implementing a entity that has multiple mutually-exclusive states. In each state, there are different set of actions (let's say, transitions) that may take the entity to a different state.

However (as expected), the set of actions depend on the state.

As a result, I faced the following question:

  • Should I expose to the public API of my entity all the possible "actions" of the entire life-cycle of my entity? Wouldn't allowing the client to make a "invalid" call be a bad public API design (because that call does not represent a valid transition for that state)?
  • If not, how should one handle this design problem?

The Concrete Example:

I am implementing a Game. It has two different states:

  • In Menu
  • Playing

Keep in mind that each state has a complex internal behavior that is not relevant for the sake of this example.

The game starts in the Menu state. When in the Menu state, when the user presses "New Game", it should change the state of the game to "Playing".

To implement this, I thought about implementing the following:

public class Game
{
    public void NewGame()
    {
        // ....
    }
}

However, of course "NewGame" should do nothing if the Game is already in the state "Playing". With that in mind, I am thinking if even allowing the client to request "NewGame" twice is a bad public API design.

That is, I am not sure if I should even allow the following to happen:

Game game = new Game(); // Starts in the "Menu" State
game.NewGame(); // Changes to the "Playing" State
game.NewGame(); // Does Nothing, because it is already in the "Playing State"

I even considered changing the name of "NewGame()" to "RequestNewGame()" to make it more obvious that it may do nothing in subsequent calls if the request is already fulfilled.


State Machine Design Pattern

Of course, I am kind of already modeling this as a State Design Pattern.

By reprashing the question in the lenses of the State Pattern: Should specific transitions be part of the wrapper class API? Or am I applying the wrong design pattern at all?

1

Yes, allowing the client to formulate invalid constructs is bad design and should be avoided if at all possible (if other factors don't force a compromise). An API is the language of your domain. If you allow invalid sentences that don't make sense you're going to confuse and frustrate your users.

So how do you model two states? Give them names (i.e. types):

public interface GameMenu {
   Game newGame();
}

public interface Game {
   ...game's functions...
}

You can make sure the user can only arrive at a Game through the menu by not exposing any other means to produce a Game instance if you want.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.