Patrón State
Parte de la sección Programación Orientada a Objetos del Journey de C# de Coddy. Lección 60 de 70.
El patrón State es un patrón de comportamiento que permite que un objeto cambie su comportamiento cuando cambia su estado interno. En lugar de usar instrucciones condicionales complejas para gestionar diferentes estados, encapsulas cada estado en su propia clase y delegas el comportamiento al objeto de estado actual.
El patrón consta de tres componentes: una interfaz de estado que define el comportamiento específico del estado, clases de estado concretas que implementan dicho comportamiento y una clase de contexto que mantiene una referencia al estado actual:
public interface IDocumentState
{
void Publish(Document doc);
}
public class DraftState : IDocumentState
{
public void Publish(Document doc)
{
Console.WriteLine("Moving to moderation");
doc.SetState(new ModerationState());
}
}
public class ModerationState : IDocumentState
{
public void Publish(Document doc)
{
Console.WriteLine("Publishing document");
doc.SetState(new PublishedState());
}
}
public class PublishedState : IDocumentState
{
public void Publish(Document doc)
{
Console.WriteLine("Already published");
}
}El contexto mantiene el estado actual y le delega las acciones. Los objetos de estado pueden activar transiciones llamando a SetState() en el contexto:
public class Document
{
private IDocumentState _state = new DraftState();
public void SetState(IDocumentState state) => _state = state;
public void Publish() => _state.Publish(this);
}
var doc = new Document();
doc.Publish(); // Pasando a moderación
doc.Publish(); // Publicando documento
doc.Publish(); // Ya publicadoEl patrón State elimina las extensas instrucciones if-else o switch que comprueban el estado actual. Cada clase de estado gestiona únicamente su propio comportamiento, lo que facilita el mantenimiento del código y su ampliación con nuevos estados.
Desafío
FácilConstruyamos un sistema de semáforo usando el patrón State. Los semáforos pasan por estados distintos (rojo, amarillo, verde), y cada estado determina qué ocurre cuando cambia la luz. En lugar de usar condicionales complejas, encapsularás cada estado de la luz en su propia clase.
Organizarás tu código en tres archivos:
TrafficLightState.cs: Define una interfazITrafficLightStateen el espacio de nombresTrafficcon un métodoChange(TrafficLight light). Después crea tres clases de estado concretas:RedState: cuando se llama aChange, imprimeRed - Stop! Changing to Green...y cambia la luz aGreenStateGreenState: imprimeGreen - Go! Changing to Yellow...y cambia aYellowStateYellowState: imprimeYellow - Caution! Changing to Red...y cambia aRedState
TrafficLight.cs: Crea una claseTrafficLighten el mismo espacio de nombres. Esta es tu clase de contexto, que mantiene el estado actual. Debe comenzar enRedStatede forma predeterminada y tener:- Un método
SetState(ITrafficLightState state)que los objetos de estado usan para activar las transiciones - Un método
Change()que delega en el métodoChangedel estado actual
- Un método
Program.cs: Une todo creando unTrafficLighty recorriendo los cambios de estado según la entrada.
Recibirás una entrada:
- El número de veces que se debe cambiar el semáforo (un entero)
Crea un TrafficLight (que comienza en rojo) y llama a Change() el número de veces especificado.
Por ejemplo, si la entrada es 3, la salida debe ser:
Red - Stop! Changing to Green...
Green - Go! Changing to Yellow...
Yellow - Caution! Changing to Red...Si la entrada es 5, la luz vuelve a recorrer el ciclo:
Red - Stop! Changing to Green...
Green - Go! Changing to Yellow...
Yellow - Caution! Changing to Red...
Red - Stop! Changing to Green...
Green - Go! Changing to Yellow...Observa que la clase TrafficLight no contiene lógica sobre lo que significa cada color ni sobre cuál viene después; todo ese conocimiento reside en las clases de estado individuales. Cada estado es responsable de su propio comportamiento y de activar la transición al siguiente estado.
Pruébalo tú mismo
using System;
using Traffic;
class Program
{
public static void Main(String[] args)
{
// Lee el número de veces que se debe cambiar el semáforo
int n = Convert.ToInt32(Console.ReadLine());
// TODO: Crea una instancia de TrafficLight (comienza en RedState por defecto)
// TODO: Llama al método Change() n veces usando un bucle
}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosNamespaces y directivasIntro a clases y objetosLa palabra clave 'this'Métodos y parámetrosCampos vs PropiedadesConstructoresInicializadores de objetosResumen - Calculadora simple4Herencia
Sintaxis básica de herencia (:)La palabra clave 'base'Palabras clave Virtual y OverrideClases selladas (Sealed)La clase base 'object'Resumen: Jerarquía de empleados7Características avanzadas
Sobrecarga de operadoresIndexadores (this[])Sobrescritura de ToString()Métodos de extensiónResumen - Lista personalizada10Patrones de diseño - Parte 1
Introducción a los patrones de diseñoSingleton Thread-SafePatrón FactoryPatrón Observer (Eventos)Patrón Strategy2Propiedades y miembros estáticos
Propiedades autoimplementadasPropiedades de solo lectura y escrituraCampos y métodos estáticosClases estáticasMiembros con cuerpo de expresión5Polimorfismo e Interfaces
Polimorfismo: Compilación vs. EjecuciónInterfaz vs. Clase AbstractaInterfaces MúltiplesInterfaces ExplícitasUpcasting y DowncastingRepaso: Calculadora de Figuras8Conceptos avanzados de POO
Composición sobre herenciaGenéricos (clases y métodos)Delegados y eventosAtributos y ReflexiónIDisposable y la sentencia usingFundamentos de Inyección de dependencias11Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón Composite3Arquitectura de clases
Datos de instancia vs. estáticosPalabras clave 'readonly' y 'const'Campos de respaldoResumen - Gestor de cuentas bancarias6Encapsulamiento
Modificadores de accesoPropiedades para el encapsulamientoImplementación de ocultamiento de datosPatrones de inmutabilidadRepaso - Registros de estudiantesPractica por tu cuenta: Compilador de C# online