Managing state in an application always presents opportunities for both brilliant and horrible designs.
I've gradually built up a utility library of objects I hope will be reusable among projects. Up until recently, though, I had not given a lot of design thought to state management. As one might suspect, that led to my code turning to spaghetti pretty quickly as states became more complex.
So, to combat the spaghettification (real word! though not in this context...) of my code, I decided to eschew enum-and-switch-based state management in favor of object-oriented management.
Instead of a case block in a humongous switch statement, each state is now its own object with its own EnterState(), Update() (for states that last longer than one frame), and LeaveState(). A managing class keeps a reference to the current state object and automates calling of the EnterState, Update, and LeaveState methods, as well as providing the interface to move to another state.
It still has some rough edges, but it provides an enormous improvement in code encapsulation and organization. Now, instead of methods scattered over one large class for all states of that class, individual state objects contain only the code relevant to that state. That translates to smaller individual classes, and therefore much easier troubleshooting when things don't go as planned.