Ciekawa, moim zdaniem, łamigłówka i zagadka projektowa. Niby każdy wie, ale nigdzie nie znalazłem ładnego wytłumaczenia.

Mamy sobie prostą maszynę stanową w postaci enuma wzbogaconego o metodę sprawdzającą dopuszczalność przejścia:

Listing 1. enum State, czyli maszyna stanowa

public enum State {

	A, B, C, D;

	private List<State> validChanage;

	static {
		A.validChanage = Arrays.asList(B);
		B.validChanage = Arrays.asList(C);
		C.validChanage = Arrays.asList(A, D);
		D.validChanage = Arrays.asList(D);
	}

	public boolean couldChange(State newState) {
		return validChanage.contains(newState);
	}
}

Takie toto prymitywne, że aż żal patrzeć… do tego mamy sobie obiekt, który wykorzystuje tego enuma do zarządzania własnym stanem:

listing 2. klasa StateObject

public class StateObject {

	private State currentState;

	public State getCurrentState() {
		return currentState;
	}

	public void setCurrentState(State currentState) {
		if (this.currentState != null 
			&& !this.currentState.couldChange(currentState)) {
			throw new IllegalStateException(
				String.format("Can not change from %s to %s", 
					this.currentState, currentState));
		}
		this.currentState = currentState;
	}
}

Teraz zagadka:

  • Czy dodanie logiki do settera jest ok? Przy czym nie jest istotne co robi logika.
  • Kiedy takie rozwiązanie jest poprawne, a kiedy nie?
  • Jeżeli nie to dlaczego?

Wersja na Stackoverflow