El Patrón de Diseño State y su aplicación al optimizador de materiales


Arquitectura Software Desarrollo Software Patrones de Diseño Design Patterns Patrones de Diseño de Comportamiento Principios SOLID Código Limpio Clean Code

En este artículo hablaremos sobre el patrón de diseño State, en ocasiones referido como "Patrón de Estado". Es el primero de una serie de artículos que publicaremos con el objetivo de hacer una explicación práctica de algunos de los patrones de diseño más usados actualmente en el desarrollo de software.

El patrón State se encuentra dentro del grupo de los patrones de comportamiento. Estos patrones definen una serie de reglas enfocadas a modelar lógica (algorítmica), así como a la asignación de responsabilidades entre diferentes objetos para llevar a cabo dicha funcionalidad.

Este patrón se encarga de permitirnos gestionar de una manera sencilla los distintos comportamientos que puede tener un objeto en función de su estado. Es realmente útil para modelar máquinas de estado sin tener que implementar complejas estructuras condicionales. La implementación correcta del patrón nos permite crear un código mucho más mantenible y escalable.

Tomando un caso real en el que hemos tenido que aplicar este patrón, se encuentra el producto Material Optimizer, ya que surgieron algunas problemáticas que generalmente aparecen en este tipo de softwares. En este caso concreto, las limitaciones en la extensibilidad y la necesidad de realizar funcionalidades más complejas para los casos críticos en el análisis de materiales requerían de comportamientos especiales en base a dichos estados. Se realizó una transformación del código para dar cabida a este patrón de comportamiento, facilitando la incorporación de técnicas de ajuste (costos y distribución) diferentes basados en los condicionantes de materiales, cadena logística y periodos de abastecimiento (estados).

Los módulos de reporting (generación de informes y visualización de pedidos) y el optimizer (evaluador de opciones y cálculo de optimizaciones) y sus componentes tenían fuertes dependencias con el estado del proceso de gestión de pedidos, por lo que se promocionó a una estructura basada en el patrón State.

namespace G4L\MaterialOptimizer\src\Domain\Order;

class MaterialOrder
{
    private $state;
    //...

    public function generateReport() {
        // clause guard: each case with a return
        if(this->state === 'created')
        {
            // report not available
        }
        if($this->state === 'processing')
        {
            // show materials project screen
        }
        if($this->state === 'optimized')
        {
            // generate PDF report for the provider
        }
        //...
        if($this->state === 'closed')
        {
            // generate PDF report with final details
        }
    }
}

Simplificación de la solicitud de materiales (módulo pedidos) y su conexión con la generación de informes para demostrar los condicionantes basados en el estado de la orden de pedido.

Como se puede apreciar en el ejemplo anterior el añadir nuevos estados a nuestros pedidos requería aumentar la complejidad del código existente teniendo que modificarlo y no pudiendo extenderlo, realizando una violación clara del principio de abierto/cerrado (OCP, Open-Close Principle).

La solución por la que nos decantamos para este problema fue la aplicación del patrón State creando una clase para cada estado del pedido y diseñando un contrato que obligase a estas clases a implementar aquellas funcionalidades dependientes del propio estado. También creamos una pieza adicional, MaterialOrder, que conoce el estado del pedido y delega la ejecución de la funcionalidad en los componentes de estado. Además, este objeto permite la transición de un estado a otro sustituyendo un objeto por otro, siendo posible gracias a que todos los estados cumplen con el contrato (interfaz) mencionado anteriormente.

Simplificación del Patrón de Diseño State en MaterialOptimizer

Diagrama de la implementación del patrón State en el producto MaterialOptimizer (caso simplificado).

Esta solución permite cumplir con el principio de responsabilidad única (SRP, Single Responsibility Principle) permitiéndonos organizar toda la lógica referente a un estado en la clase que lo representa. Además, añadir nuevos estados supone crear nuevas piezas que cumplan con el contrato creado favoreciendo el principio de abierto/cerrado.

En definitiva, la aplicación del patrón State nos permite el modelado de máquinas de estado sin la necesidad de crear voluminosas estructuras condicionales. Los contratos del patrón State establecen las funciones presentes en cada uno de los estados. Por lo tanto, a través de la encapsulación de lógica y de la abstracción obtenida por el uso de dichos contratos, podemos crear proyectos altamente escalables.

Si se quiere entender mejor los principios de desarrollo SOLID y su relación con las buenas prácticas de diseño software mencionadas en el artículo recomendamos echar un vistazo a nuestro curso especializado de Principios SOLID.

Este sitio web emplea cookies propias y de terceros para analizar el tráfico y ofrecerle una mejor experiencia. Al navegar o utilizar nuestros servicios el usuario está aceptando su uso.Más información.