2011-02-08 27 views
38

He encontrado algunas implementaciones de patrón de estado en mi experiencia de programación, y he hecho algunas. Los he visto usar en varios escenarios (principalmente UI y análisis sintáctico). El problema es que todos ellos, bajo la presión de un desarrollo rápido, se convirtieron en trozos de código difícilmente comprensibles y fáciles de mantener. Estoy considerando refaccionar uno de estos, pero estoy teniendo problemas para encontrar buenos recursos para esto en línea. Hay muchos ejemplos simples de State Pattern en línea, pero necesito algunos más recursos en profundidad.¿Cómo se usa el patrón de estado correctamente?

Así que estoy buscando:

  • ejemplos de errores comunes cuando implementar patrón de estado y cómo evitarlos ,
  • ejemplos del mundo real de patrón estado se hace correctamente (como en algunos proyecto/marco de código abierto)
  • Las experiencias personales con el estado patrón también son bienvenidas

Gracias por su tiempo

+0

No es adecuado si tiene MUCHOS estados, por ejemplo, en un juego en 3D. –

+0

Entonces, ¿qué tipo de alternativa sugieres? – Ivan

+0

¿Qué tal un enlace a la definición del patrón de estado? –

Respuesta

22

@Ivan: hay una serie de recursos disponibles en la web para Hierarchical State Machines (HSM). Miro Samek ha escrito extensamente sobre este patrón de diseño y ofrece mucha información útil.

Algunos de los artículos que deben ser de interés:

La gran ventaja de utilizar HSM sobre gráficos de estado de FSM planas descri La cama de Mealy y Moore es que la jerarquía crea una separación de responsabilidad. Los estados secundarios solo necesitan manejar aquellas condiciones para las que están expresamente diseñados: los eventos no administrados se pasan al estado principal, si el estado principal no está diseñado expresamente para manejarlo, entonces se pasa al siguiente nivel superior. padre y así sucesivamente Le permite crear máquinas de estado pequeñas y manejables que tienen un único propósito, una que puede caber dentro de un solo objeto. A medida que se agregan nuevas características, o cuando se agregan nuevas clases, solo necesitan manejar su propia pequeña parte del mundo y transmitir los eventos no controlados a sus respectivos padres.

Cuando se implementa correctamente, obtiene un programa robusto con baja complejidad ciclomática, que es fácil de modificar o actualizar según sea necesario.

+0

Gran respuesta y enlaces – neuro

7

Apenas mis 2 centavos, el patrón de estado siempre se vuelve difícil de mantener, ya que es difícil de entender para quienes no lo han codificado. Por lo general, me reincorpo a la matriz estándar anterior de punteros de función/método, como lo hice en mi antigua experiencia en C. Usted acaba de construir una matriz de dos dimensiones de indicadores de función con estado/señal para líneas/columnas. Más fácil de entender. usted tiene una clase que manejar eso y delegar a otra clase para manejar la complejidad ...

MY2C

+2

+1 idea interesante ... ¿tiene una muestra en algún lugar? –

+0

@Pangea: alas no en mi base de código actual. Trataré de agregar código en mi respuesta si tengo tiempo ... – neuro

6

La mayoría de las veces, los estados en un diseño de patrón de estado están manejando más de un estado (o de subestados el estado) que hace que sea más difícil de mantener.

Si un estado tiene algún tipo de selección, se trata principalmente de más de un estado.

Me toma mucha disciplina para mantener limpios los estados.

Una posible solución a esto es crear estados más complejos statemachines (HSM). Esto lo hace mucho más legible en el nivel superior porque tiene que tratar con menos estados.

+0

Este criterio: "Si un estado tiene algún tipo de selección, se trata principalmente de más de un estado". es muy útil para averiguar si debe dividir el estado en dos. –

4

echar un vistazo a Finite State Machine. Casi todos los lenguajes maduros tienen buenos ejemplos propios. Como no ha especificado su idioma preferido, le daré un ejemplo de C++: Boost FSM library. Lo más probable es que sea mucho más complicado de lo que necesita, pero puede darle algunos consejos de diseño con seguridad

1

Debe usar el patrón de estado, si tiene un comportamiento diferente para cada estado. Quizás necesites reconfigurar las transiciones en tiempo de ejecución. Otra razón para usarlo es que quizás deba agregar más estados más adelante.

Imagine un juego de tablero como las Damas chinas tiene diferentes estados de GUI para elegir un Peón, seleccione un espacio de destino y así sucesivamente. En cada estado, la GUI debe comportarse de manera diferente, algunas entradas deben ser manejadas y otras ignoradas. Es posible usar un interruptor/caja simple, pero el patrón de estado es útil ya que la lógica está encapsulada, el código relacionado es el mismo. Esto facilita la introducción de nuevos estados sin afectar a la mayoría de los demás estados (dependiendo de quién sea el responsable de establecer las transiciones: o bien el estado conoce sus transiciones salientes, o bien podrían darse en tiempo de ejecución, por ejemplo, usando el constructor).

Como puede ver en this example, el GuiController usa una interfaz IGuiState para cambiar su comportamiento bajo demanda. Una implementación can be seen here.

El principal inconveniente es utilizar el interruptor/caja, cuando necesite flexibilidad. Dado que la indirección toma un poco más de tiempo, lo recomendaría para una cantidad fija de declaraciones bastante simples. Tengo que implementar un protocolo de red de bajo nivel bastante rápido, que suele ser muy costoso.

23

Como probablemente haya leído, el State Design Pattern es útil cuando el estado varía el comportamiento de algún objeto cuya composición incluye ese estado. Esto implica la idea de una clase abstracta State, interfaz, o enumerated type - aunque dependiendo del idioma Duck Typing también lo hará - que define cualquier comportamiento común y/o métodos requeridos.

aspectos clave

En realidad, hay dos aspectos importantes a considerar en el trabajo con el patrón de estado: enumeración y de transición. La enumeración simplemente significa identificar el conjunto de estados posibles (por ejemplo, días de la semana) o más abstractivamente los tipos de estados (es decir, metaestados) como inicio, finalización y en el medio para un motor de flujo de trabajo. Transición significa decidir cómo modelar el movimiento entre estados donde esto normalmente se hace capturando todas las transiciones posibles en una representación tabular (es decir, Finite State Machine) o hace que cada estado conozca sus posibles "transiciones" a otros estados.

Normalmente, las transiciones van de la mano con los metaestados porque no es posible conocer todos los estados y relaciones por adelantado en un sistema tan dinámico donde se pueden agregar nuevos estados, y por lo tanto transiciones, en tiempo de ejecución. Además, con el enfoque de transición, cierto comportamiento-notificaciones por ejemplo-se convierte en parte de la transición, en lugar del estado mismo.

Ejemplos

Hay varios escenarios, ya sea que he trabajado o discutidos, donde se trata de una instalación de uso:

  1. flujo de trabajo
  2. juego de ordenador oponente A.I.
  3. Proceso orquestación

Por flujo de trabajo quiero decir algo así como jBPM. Los sistemas de este tipo se preocupan por controlar la atención adecuada de las personas adecuadas en el momento adecuado. Por lo general, envían muchos correos electrónicos u otro tipo de notificación. Y, el proceso que representan necesita la capacidad de cambiar a medida que la organización cambia, mientras que los datos que se administran normalmente cambian mucho más lentamente.

Ordenador Juego oponente A.I. se explica por sí mismo. No es algo que haya escrito, pero en una conversación con quienes lo han hecho, estos sistemas suelen ser autónomos. En otras palabras, a diferencia del flujo de trabajo, el juego generalmente no tiene la capacidad de alterar el proceso utilizado para controlar a los oponentes de la computadora.

Orchestration de proceso es similar al flujo de trabajo, pero se enfoca en la integración del sistema, en lugar de interacción con personas. El marco Apache Mule es un ejemplo. Aquí el estado puede describir el estado (por ejemplo, iniciado, en proceso, finalizado) y tipo (por ejemplo, punto de integración ftp, punto de integración sql).

Conclusión

A diferencia de otras respuestas, creo que la encapsulación del estado es una excelente manera de gestionar el cambio de sistemas de software. Hecho bien, facilita esos cambios o permite a los usuarios hacerlo en tiempo de ejecución. Usted hace una compensación de más flexibilidad a cambio de una mayor complejidad de implementación. Entonces, tal enfoque probablemente no sea útil para el carro de compras, por ejemplo, donde el comportamiento es probablemente muy conocido y no le gusta cambiar. Por otro lado, cuando el proceso está sujeto a cambios, encaja muy bien.

0

Estoy construyendo un evaluador de expresiones que tiene la capacidad de evaluar conjuntos de elementos. Encontré que el patrón de estado es muy útil para discriminar lo que se puede y no se puede hacer a un conjunto dependiendo de su estado. es decir: abierto, cerrado, inactivo, activo ect. Los FSM son muy fáciles de dibujar y reducen la complejidad del código al eliminar la necesidad de grandes bloques de declaraciones ifelse para definir qué debe hacer la característica dependiendo de sus atributos adjuntos. Hace que estas condiciones sean más explícitas al convertir las condiciones en clases. Es uno de mis patrones favoritos hasta ahora.

2

Así que estoy buscando:

  • ejemplos de errores comunes al implementar el patrón del estado y cómo evitarlos,

El patrón de estado no escala bien. Imagínese una máquina de estado con 10 estados y 10 tipos de transición diferentes. Agregar un nuevo estado significa que el estado tiene que definir las 10 transiciones. Agregar una nueva transición significa que los 10 estados deben definirla. En resumen, no use el patrón de estado si su máquina de estado no es estable y/o tiene muchos estados/transiciones.

  • ejemplos del mundo real de patrón de estado se hace correctamente (como en algún proyecto de código abierto/marco)

Definir correctamente :-) El ejemplo citado en Java https://stackoverflow.com/a/2707195/1168342 es para JSF Ciclo de vida, pero creo que solo hay una transición. Ninguna de las otras respuestas cita nada para el Estado.

  • experiencias personales con el modelo de estado también son bienvenidos

Head First Design Patterns uses a Gumball machine example para ilustrar Estado. Es irónico, pero cada vez que extienden el diseño (agregando un nuevo estado o transición), hay un montón de código repetido (especialmente para las transiciones inválidas dentro de estados específicos). Además, de acuerdo con quién decide cuál es el siguiente estado, las clases de estados individuales se pueden acoplar entre sí (dependencias entre estados). Consulte la explicación al final de esta respuesta: https://stackoverflow.com/a/30424503/1168342.

El libro de GoF menciona que table-based alternatives tiene ventajas, a saber, su regularidad. Cambiar los criterios de transición requiere cambiar la tabla (y no el código).

+0

¡Gran respuesta! Gracias. – Ivan

Cuestiones relacionadas