JS: Polimorfismo
Teoría: Patrón Estado (State)
El patrón Estado es un claro ejemplo de reemplazo de construcciones condicionales por polimorfismo de subtipos. Se utiliza ampliamente y puede reducir realmente la complejidad del código. Vamos a analizarlo utilizando como ejemplo el comportamiento de las pantallas de los celulares.
Aunque no todos los celulares se comportan igual, para esta lección elegiremos un ejemplo específico..
El celular tiene tres estados básicos:
- Сelular apagado. La pantalla no responde a los toques.
- Сelular encendido, pero pantalla apagada. La pantalla responde solo a los toques (no a los deslizamientos) y se enciende.
- Сelular y pantalla encendidos. La respuesta a los toques y gestos depende de la aplicación activa.
Vamos a modelar esta lógica en una clase que se encargue de la pantalla, y agregaremos dos eventos: toque (tap) y deslizamiento (swipe).
Hay solo dos eventos, pero ya hay muchas construcciones condicionales. En realidad, habría muchos más eventos y todos ellos deberían tener en cuenta el estado activo del celular y la pantalla.
Si resolvemos este problema de manera directa, obtendremos una gran cantidad de construcciones condicionales en cada método de evento. Este código es muy complejo y frágil. Cambiar la cantidad de estados y agregar nuevos eventos conlleva el riesgo de introducir errores constantemente. Es difícil ver el panorama general y no perder nada.
La complejidad de este código se puede reducir significativamente mediante dos transformaciones sucesivas: la extracción explícita del estado y la introducción del polimorfismo de subtipos.
Estado explícitamente extraído
La implementación actual de la pantalla se basa en banderas. En programación, se llaman banderas a las variables que contienen valores booleanos.
Las banderas a menudo (pero no siempre) son un indicio de una mala arquitectura. Tienden a multiplicarse y superponerse. La lógica basada en combinaciones de diferentes banderas dificulta el análisis del código:
Este estilo de programación tiene un nombre: "programación basada en banderas". Así se llama al código que es difícil de entender debido a la presencia de lógica basada en la combinación de banderas. Y la presencia de banderas casi siempre lleva a esto. Todo se debe a que el número de estados en los sistemas suele ser mayor que dos. Es decir, una sola bandera nunca es suficiente.
Es posible evitar las banderas introduciendo un estado explícito del sistema. En nuestro ejemplo, es fácil ver que hay tres estados:
- Apagado: el celular está apagado (y, por lo tanto, la pantalla también está apagada).
- Desactivado: la pantalla está apagada (pero el celular está encendido).
- Encendido: la pantalla está encendida.
El siguiente paso es reemplazar las banderas por una sola variable que almacene el estado actual del sistema:
Lo más importante que sucedió en el código anterior es que desaparecieron las comprobaciones de combinación de banderas. Esto no significa que no se puedan realizar comprobaciones con varios estados a la vez, pero es mucho más fácil entender los estados del sistema que las combinaciones de banderas.
Clases de estados
Para eliminar las construcciones condicionales, necesitaremos polimorfismo. ¿En qué se basa? Gracias a la presencia de un estado explícitamente extraído, es fácil ver la dependencia del comportamiento del estado. Son los estados los que deben convertirse en clases con su propio comportamiento específico para ese estado.
A su vez, la pantalla se librará de todas las comprobaciones y comenzará a interactuar con los estados:
Ahora la pantalla no hace absolutamente nada. Todo su código es la inicialización del estado inicial y la transferencia del control al estado activo actual. ¿Cómo se ven las clases de estado?
El estado del celular apagado es el más simple. En este estado no hay ninguna reacción, por lo que los métodos están vacíos. Veamos EstadoDesactivado:
Tocar la pantalla la activa. Para ello, el estado EstadoDesactivado debe cambiar al estado EstadoEncendido. Por eso se pasa la propia pantalla a cada estado. De lo contrario, no sería posible cambiarla.
Y finalmente, el último estado EstadoEncendido. Este es el único estado en el que se produce la interacción con las aplicaciones.
Es increíble, pero el código ya no tiene ninguna estructura condicional. Ahora es fácil ver el comportamiento del teléfono ante cualquier evento en un estado específico con solo abrir la clase correspondiente. La comodidad de este enfoque implica tener más archivos y código.
Es muy importante no perder la idea principal del patrón. Las clases de estado se introducen solo para introducir el polimorfismo, pero no tienen sus propios datos para trabajar. Al final, todas las acciones se realizan en la propia pantalla, la entidad que estamos simplificando.
Completado
0 / 14