Patrón State

[ Arquitectura  ]

El patrón State nos ayuda a que un objeto se comporte de forma diferente según un flag de estado. De esta forma, según cual sea el flag de estado, el objeto se comportará de una forma o de otra.

El ejemplo más simple para entender este patrón, es en los pedidos, si el pedido ha pasado por todos los estados y ha llegado al estado “Pedido Entregado”, no tiene sentido que podamos ejecutar un método que lo que haga es cambiar la dirección de entrega, a pesar de que internamente, este objeto(pedido) tenga ese método y que sin embargo, solo se pueda ejecutar mientras el objeto está en “Preparando el envío”.

Vayamos con el ejemplo:

public class PedidoState {
    protected IList<ProductoState> productos = new List<ProductoState>();

    public IList<ProductoState> Productos => productos;

    protected EstadoPedido EstadoPedido;

    public PedidoState() {
        EstadoPedido = new PedidoEnCurso(this);
    }

    public void AgregaProducto(ProductoState producto)
    {
        EstadoPedido.AgregaProducto(producto);
    }

    public void QuitaProducto(ProductoState producto)
    {
        EstadoPedido.QuitaProducto(producto);
    }

    public void QuitaTodo()
    {
        EstadoPedido.QuitaTodo();
    }

    public void EstadoSiguiente()
    {
        EstadoPedido = EstadoPedido.EstadoSiguiente();
    }

    public void Imprime()
    {
        Console.WriteLine("Contenido del pedido:");
        foreach (var producto in Productos)
        {
            producto.Imprime();
        }

        Console.WriteLine();
    }
}

public abstract class EstadoPedido {
        protected PedidoState Pedido;

        protected EstadoPedido(PedidoState pedido) {
            Pedido = pedido;
        }

        public abstract void AgregaProducto(ProductoState producto);
        public abstract void QuitaTodo();
        public abstract void QuitaProducto(ProductoState producto);
        public abstract EstadoPedido EstadoSiguiente();
}

public class PedidoEnCurso : EstadoPedido {
    public PedidoEnCurso(PedidoState pedido) : base(pedido) { }

    public override void AgregaProducto(ProductoState producto)
    {
        Pedido.Productos.Add(producto);
    }

    public override void QuitaTodo()
    {
        Pedido.Productos.Clear();
    }

    public override void QuitaProducto(ProductoState producto)
    {
        Pedido.Productos.Remove(producto);
    }

    public override EstadoPedido EstadoSiguiente()
    {
        return new PedidoConfirmado(Pedido);
    }
}

public class PedidoConfirmado : EstadoPedido {
    public PedidoConfirmado(PedidoState pedido) : base(pedido) { }

    public override void AgregaProducto(ProductoState producto)
    {
    }

    public override void QuitaTodo()
    {
        Pedido.Productos.Clear();
    }

    public override void QuitaProducto(ProductoState producto)
    {
    }

    public override EstadoPedido EstadoSiguiente()
    {
        return new PedidoEntregado(Pedido);
    }
}

public class PedidoEntregado : EstadoPedido {
    public PedidoEntregado(PedidoState pedido) : base(pedido) { }

    public override void AgregaProducto(ProductoState producto) { }

    public override void QuitaTodo() { }

    public override void QuitaProducto(ProductoState producto) { }

    public override EstadoPedido EstadoSiguiente()
    {
        return this;
    }
}

public class Producto {
    public class ProductoState
    {
        protected string Nombre;

        public ProductoState(string nombre)
        {
            Nombre = nombre;
        }

        public void Imprime()
        {
            Console.WriteLine($"Producto: {Nombre}");
        }
    }
}

public class Usuario {
    static void Main(string[] args) {
        PedidoState pedido = new PedidoState();
        pedido.AgregaProducto(new ProductoState("Book 1"));
        pedido.AgregaProducto(new ProductoState("Book 2"));
        pedido.Imprime();
        pedido.EstadoSiguiente();
        pedido.AgregaProducto(new ProductoState("Book 3"));
        pedido.QuitaTodo();
        pedido.Imprime();

        PedidoState pedido2 = new PedidoState();
        pedido2.AgregaProducto(new ProductoState("Book 10"));
        pedido2.AgregaProducto(new ProductoState("Book 20"));
        pedido2.Imprime();
        pedido2.EstadoSiguiente();
        pedido2.Imprime();
        pedido2.EstadoSiguiente();
        pedido2.QuitaTodo(); //En este estado no hará nada
        pedido2.Imprime();
    }
}



@2017/@2024 - JRRN