Introducció al Patró State

El patró State és un patró de disseny de comportament que permet a un objecte canviar el seu comportament quan el seu estat intern canvia. Aquest patró és especialment útil quan un objecte ha de canviar el seu comportament en funció del seu estat, i aquests canvis de comportament són complexos o nombrosos.

Conceptes Clau

  • Context: L'objecte que conté l'estat actual i delega el comportament a l'estat.
  • State: Una interfície o classe abstracta que defineix el comportament associat a un estat particular del context.
  • Concrete States: Implementacions concretes de la interfície State que defineixen el comportament específic per a un estat particular.

Diagrama UML

+-----------------+          +-----------------+
|     Context     |          |      State      |
+-----------------+          +-----------------+
| - state: State  |<>--------| + handle(): void|
+-----------------+          +-----------------+
| + request(): void|          +-----------------+
+-----------------+                    ^
                                       |
                                       |
                             +-----------------+
                             | ConcreteStateA  |
                             +-----------------+
                             | + handle(): void|
                             +-----------------+
                                       ^
                                       |
                             +-----------------+
                             | ConcreteStateB  |
                             +-----------------+
                             | + handle(): void|
                             +-----------------+

Exemple Pràctic

Suposem que estem desenvolupant una màquina de cafè que té diferents estats: Ready, Brewing, i OutOfService. Cada estat té un comportament diferent quan es prem el botó de començar.

Implementació en Java

// Interfície State
interface State {
    void handleRequest();
}

// Estat concret: Ready
class ReadyState implements State {
    private CoffeeMachine coffeeMachine;

    public ReadyState(CoffeeMachine coffeeMachine) {
        this.coffeeMachine = coffeeMachine;
    }

    @Override
    public void handleRequest() {
        System.out.println("Starting the brewing process...");
        coffeeMachine.setState(coffeeMachine.getBrewingState());
    }
}

// Estat concret: Brewing
class BrewingState implements State {
    private CoffeeMachine coffeeMachine;

    public BrewingState(CoffeeMachine coffeeMachine) {
        this.coffeeMachine = coffeeMachine;
    }

    @Override
    public void handleRequest() {
        System.out.println("Already brewing coffee...");
    }
}

// Estat concret: OutOfService
class OutOfServiceState implements State {
    private CoffeeMachine coffeeMachine;

    public OutOfServiceState(CoffeeMachine coffeeMachine) {
        this.coffeeMachine = coffeeMachine;
    }

    @Override
    public void handleRequest() {
        System.out.println("Machine is out of service.");
    }
}

// Context: CoffeeMachine
class CoffeeMachine {
    private State readyState;
    private State brewingState;
    private State outOfServiceState;

    private State currentState;

    public CoffeeMachine() {
        readyState = new ReadyState(this);
        brewingState = new BrewingState(this);
        outOfServiceState = new OutOfServiceState(this);

        currentState = readyState; // Initial state
    }

    public void setState(State state) {
        currentState = state;
    }

    public void pressButton() {
        currentState.handleRequest();
    }

    public State getReadyState() {
        return readyState;
    }

    public State getBrewingState() {
        return brewingState;
    }

    public State getOutOfServiceState() {
        return outOfServiceState;
    }
}

// Client
public class StatePatternDemo {
    public static void main(String[] args) {
        CoffeeMachine coffeeMachine = new CoffeeMachine();

        coffeeMachine.pressButton(); // Starting the brewing process...
        coffeeMachine.pressButton(); // Already brewing coffee...

        coffeeMachine.setState(coffeeMachine.getOutOfServiceState());
        coffeeMachine.pressButton(); // Machine is out of service.
    }
}

Exercici Pràctic

Enunciat

Implementa un sistema de semàfor utilitzant el patró State. El semàfor ha de tenir tres estats: Red, Yellow, i Green. Cada estat ha de tenir un comportament diferent quan es canvia l'estat.

Solució

// Interfície State
interface TrafficLightState {
    void change(TrafficLight trafficLight);
}

// Estat concret: Red
class RedState implements TrafficLightState {
    @Override
    public void change(TrafficLight trafficLight) {
        System.out.println("Changing from Red to Green...");
        trafficLight.setState(new GreenState());
    }
}

// Estat concret: Yellow
class YellowState implements TrafficLightState {
    @Override
    public void change(TrafficLight trafficLight) {
        System.out.println("Changing from Yellow to Red...");
        trafficLight.setState(new RedState());
    }
}

// Estat concret: Green
class GreenState implements TrafficLightState {
    @Override
    public void change(TrafficLight trafficLight) {
        System.out.println("Changing from Green to Yellow...");
        trafficLight.setState(new YellowState());
    }
}

// Context: TrafficLight
class TrafficLight {
    private TrafficLightState state;

    public TrafficLight() {
        state = new RedState(); // Initial state
    }

    public void setState(TrafficLightState state) {
        this.state = state;
    }

    public void change() {
        state.change(this);
    }
}

// Client
public class TrafficLightDemo {
    public static void main(String[] args) {
        TrafficLight trafficLight = new TrafficLight();

        trafficLight.change(); // Changing from Red to Green...
        trafficLight.change(); // Changing from Green to Yellow...
        trafficLight.change(); // Changing from Yellow to Red...
    }
}

Errors Comuns i Consells

  • No encapsular l'estat: Assegura't que l'estat estigui encapsulat dins del context i que només es pugui canviar a través de mètodes definits.
  • No definir comportaments específics en el context: Mantingues els comportaments específics dins de les classes d'estat concret per seguir el principi de responsabilitat única.
  • No gestionar correctament les transicions d'estat: Assegura't que les transicions d'estat siguin clares i gestionades adequadament per evitar inconsistències.

Resum

El patró State permet que un objecte canviï el seu comportament quan el seu estat intern canvia. Aquest patró és útil per gestionar comportaments complexos que depenen de l'estat de l'objecte. Hem vist un exemple pràctic amb una màquina de cafè i un exercici amb un sistema de semàfor. A més, hem destacat alguns errors comuns i consells per evitar-los.

© Copyright 2024. Tots els drets reservats