Finite State Machine Pattern - The One True Patter

2020-02-17 06:58发布

问题:

Could all Code ever written be improved by applying the State Machine Pattern?

I was working on a project that was a mass of horrendous awful, buggy, broken spaghetti code. I copied Martin Fowler's example State Machine code from this blog and transformed the whole heap of crap into a series of statements. Literally just a list of States, Events, Transitions and Commands.

I can't believe the transformation. The code is now clean, and works. Of course i was aware of State Machines before and have even implemented them but in the Martin Fowler example the separation of model/configuration is amazing.

This makes me think that almost everything i've ever done could have benefitted in some way from this approach. I want this functionality in every language i use. Maybe this should even be a language level feature.

Anyone think this is wrong? Or anyone have a similar experience with a different pattern?

回答1:

Finite state machines (FSM's) and more specifically domain specific languages (DSL's) make it easier to match a problem to one specific solution domain, by describing the solution in a specialised language.

The limitations of the State Machine pattern is that it itself constitutes a programming language, but one for which you have to write your own execution, testing and debugging tools; and one which any maintainer has to learn. You have moved the complexity of your code into a complex FSM configuration. Occasionally, this is useful, but certainly not universally.

And since any von Neumann computer is itself a FSM, then certainly any program can be recast in this fashion.



回答2:

Spaghetti code is never the right answer. Patterns are good at cleaning up spaghetti code, but just having a well thought out design can achieve the same thing.

With respect to the state-machine question: I personally find them to be very useful. For a public facing app I created, I refactored to use a state-chart (which I think is the same thing as the state-machine) and noticed the benefits you mentioned. It is a really useful abstraction, because it allows you to separate the concern of handling events out into a separate component. With this, bugs go away because the state-chart implicitly knows what a user can do where, and since the events are only handled in the right place, you can't really perform an invalid action. Also, using the state-chart allowed me to simplify the code because I could pull all the event handling code out of where it was and put it where it in one place where it was supposed to be -- in other words, other components weren't complicated by also having event handlers on them.

A picture is worth a thousand works -- Here is the design I came up with:

With this, anyone who looks at it knows exactly how the app behaves at a high level. Its hard to break this, because like I said, you can't get to an invalid state because the event handlers control exactly where you can go; if you can get to an invalid state, its an implementation bug that is easily fixed. Also, the code cleansing benefits are enormous. For example, with the state chart, whenever I enter any paused state, I can do things like stop the clock, put a mask on the board, etc. Its a few lines of code in one place -- because when i enter a substate of paused the chart goes thru the parent state first. without the statechart, I would have to do that code everywhere an event was handled.

I don't know if it needs to be a language level feature, but having a well implemented framework is nice.