Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'm working (a bit) on a (turn-based strategy) game. There are two classes relevant for the question:

  • State: This is an immutable class, which exposes all its fields (either via getters or another way, as I felt appropriate). The state is a bit complicated, so I decomposed it into several classes in the package ...state
  • Command: This is an abstract immutable class with a couple of subclasses like MoveCommand(Field from, Field to), PassCommand(), BidCommand(int amount), etc. in the package ...command. All of fields have public getters.

I need one of the two methods

  • State Command.applyTo(State) or
  • State State.apply(Command)

returning the new state (obtained by applying the command to the state).

Using the first method looks better at the first sight, since it dispatches to different implementations of applyTo in the subclasses of Command. Unfortunately, it forces me to fiddle with the many details of State in the class Command. In order to make it work, I need something like MutableState, or State.Builder, or a many-args constructor of State, or whatever.

Using the second method looks ugly, as it'd force me to use instanceof (or some other ugly way to simulate the virtual method dispatch). OTOH, it would concentrate the working with State in the class itself.

So I think the first method is the way to go. With Command and State each in its own package it means that MutableState (or whatever gets used for building the resulting State) need to be a public class since there are no friends in Java. No real problem, but not nice, is it?

So what is the proper design?

share|improve this question
4  
Why is State immutable? That's almost contradictory. Immutable means stateless. Stateful means mutable. I don't get why you've created this problem for yourself. Can you explain further how state can be immutable? –  S.Lott Sep 12 '11 at 21:57
    
@S.Lott: I don't claim it's a good idea. The State never changes, it just gets replaced by another one (created from the MutableState). I'm considering dropping immutability but it wouldn't help much: The problem of Command fiddling with its data remains. –  maaartinus Sep 12 '11 at 22:25
    
"The problem of Command fiddling with its data remains"? The state has an API, does it not? The Command uses that API to make change to the state, correct? How is this a "problem"? Please be more specific. –  S.Lott Sep 12 '11 at 22:41
1  
I'm leaning towards S.lott's thinking here. To me, State should be mutable, although strictly bounded through an enum or similar tight design. YMMV of course –  Martijn Verburg Sep 12 '11 at 23:10
1  
@S. Lott, but that's exactly with the OP is doing. He's just got an object which is much more complex then a 2. He was a pointer to the current state. To change the state he replaces the object that pointer points to. Just like how you'd increment a count by replacing the integer object. –  Winston Ewert Sep 13 '11 at 0:54

5 Answers 5

Don't get too caught up on the State Pattern. This has a specific usage which I don't think necessarily applies in your game, at least not when you are manipulating the state of play.

Take, for example, a drawing application. In this case, the button pressed in the toolbar affects the way the drawing panel reacts to certain stimuli -- in this case, you don't want the application to know what it is going to do, you just want it to pass the stimulus to the State object and let it figure out what to do.

So, the rectangle drawing button is down, the application holds a RectangleDrawingState from which it can request a mouse-over pointer type or a mouse-down action or whatever. If you press the elipse-drawing button then that control switches out the RectangleDrawingState for an ElipseDrawingState and the application continues to ask for a mouse-over pointer type and a mouse-down action and gets completely different responses.

This is the kind of situation that makes for a good use-case for the State Pattern.

Now you may want this in your turn-based strategy game, to handle whether the attack button is pressed or the gather resources button is pressed. But you should handle the state of the game differently.

The state of the game should be handled as a single mutable object, which is manipulated at the end of each action. This object needs to be serializable in some form.

What you should do then is get a Command object by whatever means necessary and act on the mutable state-of-play object (it might be that your immutable State object, which depends on the action selected at any given time, returns a command which can act on the state-of-play object, for example).

share|improve this answer
    
I don't the see the OP is using the state pattern. –  Winston Ewert Sep 13 '11 at 0:23
    
@Winston: Hard to be sure, now I read it back. That's how I took it, but you could be right. –  pdr Sep 13 '11 at 1:16
    
@pdr: I am actually using neither the State nor the Command Patterns; in fact my State is final (but I'm going to use the Command Pattern for sending commands to the opponent). The classes just represent the state of the game and the user supplied command. –  maaartinus Sep 13 '11 at 20:01
    
@maaartinus: Ok, sorry for misunderstanding, although the design I describe in the second half of the answer is still relevant, I believe. As for Undo, take a look at the Memento Pattern. –  pdr Sep 13 '11 at 20:05
    
@pdr: My bad, I was quite confused as I was writing my question. Your answer was useful, anyway. –  maaartinus Sep 17 '11 at 12:04

It sounds like you already know that Solution 2 is a bad plan. But solution 1 is giving you trouble as well.

I gather your classes end up looking like this:

class MoveCommand
{
   MoveCommand(Field from, Field to)
   {
      this->from = from;
      this->to = to;
   }

   State apply(State state)
   {
       MutableState mutable_state = new MutableState(state);
       Unit unit = mutable_state.GetUnit(from);
       mutable_state.RemoveUnit(from);
       mutable_state.PutUnit(to, unit);
       return mutable_state.AsState();
   }
}

Firstly, you've designed your immutable objects wrong. The idea is not to switch back and forth between immutable and mutable objects. Rather, if you want to use immutable objects, then methods on your immutable object should return new objects. So your code should look more like this.

State apply(State state)
{
    Unit unit = state.GetUnit(from);
    state = state.RemoveUnit(unit);
    state = state.PutUnit(to, unit);
    return state;
}

But immutability is great for small things like numbers, strings, etc. For handling the entire state of your game, it tends to get cumbersome. So really, I figure you should drop the immutable aspect and do:

void apply(State state)
{
    Unit unit = state.GetUnit(from);
    state.RemoveUnit(unit);
    state.PutUnit(to, unit);
}

However, an argument can be made that this makes the MoveCommand have logic that belong somewhere else. Perhaps the code should look like:

void apply(State state)
{
    state.move(from, to);
}

But this makes the whole MoveCommand class look a little pointless because it doesn't seem to really do anything. But I say: don't worry about it. Some commands will be trivially implemented using the game state objects. And that's a good thing.

share|improve this answer
    
Currently my classes indeed look like your first example, and I'm starting to like it. Using both the mutable and immutable state allows me to separate responsibilities better. I'll implement a bit more and see. –  maaartinus Sep 17 '11 at 12:03

I think you're fine using your first method. You will probably want to utilize a StateBuilder to allow the command to build out the new state.

Thus you've divided your state, your commands (allowing you to roll back to prior states, I assume), and your means of building new states.

That said, I'm not sure what the immutable state is giving you in this case, beyond something with a handle that can be tracked or rolled back to. If that is not your purpose, I don't know that you need it.

share|improve this answer
    
I think you're quite right. There are some advantages of the immutable State (thread-safety, clarity, and trivial rollback), but I'm not sure if it's worth it. Currently I've made some progress using both State and MutableState, and it looks fine. The overhead for having two such classes may be worth it. –  maaartinus Sep 13 '11 at 20:06

Perhaps you should separate Command (a request) from its affects (a response). You have a set of concrete Command classes and the State objects will behave differently for each, so you should consider using overloaded methods for each Command. This allows you to specifically handle each Command as only the State should know how to respond. You Command objects have no inherent behaviour, only the data needed for the request.

void State.Handle(MoveCommand)

void State.Handle(PassCommand)

void State.Handle(BidCommand)

The Handle methods are responsible for validating the Command against current state, and then raising appropriate domain events to affect the state of the model. The domain events contains the new data to be applied interested parties (e.g. 'MovedEvent' contains new position).

The Apply methods accept concrete domain event objects and change the state accordingly:

void State.Apply(MovedEvent)

void State.Apply(PassedEvent)

void State.Apply(BiddedEvent)

Domain events could also be routed to other affected objects.

share|improve this answer

I ended up with some mixed design:

  • The state consists of two parts:
    • StateData representing
      • the board
      • the card stacks of both players
      • and other long-term things
    • StateControl representing the intermediate steps like
      • when a player has selected an own unit as an attacker, but not yet the target
      • when one of many similar transient situation occurs

The latter uses the state pattern. Everything is immutable and I've dropped the mutable counterpart. With the help of Lombok Wither, it works just fine.

I'm using Command.applyTo(State) which sometimes just delegates to helper methods State.apply(Command), so there are actually both variants.

The immutability lead to some unnecessary allocations like

State move(Field from, Field to) {
    State result = this;
    Group g = getGroupFromField(from);
    result = state.withField(from, EMPTY_GROUP); // throw-away state
    result = state.withField(to, g);
    return result;
}

but short-living objects are cheap and the object is actually rather small as it consists of a couple of references to other small immutable objects.

The immutability also made the code a bit longer, but surely less error-prone. It also saved me from coding any copying methods and I believe it'll show its advantages when/if I code the game AI.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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