Design patterns: State

Mauto 3 min

Lo State Pattern è un pattern comportamentale che permette a un oggetto di modificare il proprio comportamento in base al proprio stato interno. Questo pattern è utile quando un oggetto deve cambiare il suo comportamento durante il runtime a seconda di uno stato che varia dinamicamente. Invece di usare una serie di condizionali per gestire i vari stati, il pattern incapsula ogni stato in una classe separata, permettendo un design più ordinato e scalabile.

Punti di Forza

  1. Riduzione del codice condizionale complesso: Evita l’uso di numerosi if-else o switch-case per determinare il comportamento in base allo stato.
  2. Aggiunta di nuovi stati: Aggiungere nuovi stati è semplice e non richiede modifiche alle classi esistenti, favorendo l’estensibilità del codice.
  3. Separazione delle responsabilità: Ogni stato viene incapsulato nella propria classe, separando chiaramente il comportamento specifico di ogni stato.
  4. Facilita il mantenimento: Modifiche al comportamento di un singolo stato non impattano le altre parti del codice.
  5. Migliore gestione del ciclo di vita degli stati: Il pattern permette di gestire le transizioni tra stati in modo esplicito e controllato.

Caso d’uso: Macchina da caffè

Immagina di avere una macchina da caffè che può trovarsi in diversi stati: Senza moneta, Con moneta, Erogazione caffè. A seconda dello stato, l’interazione con la macchina cambia.

Codice PHP

// Interfaccia per gli stati
interface CoffeeMachineState {
    public function insertCoin();
    public function pressButton();
    public function dispense();
}

// Stato Senza Moneta
class NoCoinState implements CoffeeMachineState {
    private $machine;

    public function __construct($machine) {
        $this->machine = $machine;
    }

    public function insertCoin() {
        echo "Moneta inserita.\n";
        $this->machine->setState($this->machine->getHasCoinState());
    }

    public function pressButton() {
        echo "Inserisci una moneta prima di premere il pulsante.\n";
    }

    public function dispense() {
        echo "Nessun caffè erogato.\n";
    }
}

// Stato Con Moneta
class HasCoinState implements CoffeeMachineState {
    private $machine;

    public function __construct($machine) {
        $this->machine = $machine;
    }

    public function insertCoin() {
        echo "Moneta già inserita.\n";
    }

    public function pressButton() {
        echo "Pulsante premuto. Erogazione in corso.\n";
        $this->machine->setState($this->machine->getDispensingState());
    }

    public function dispense() {
        echo "Premi il pulsante prima di ottenere il caffè.\n";
    }
}

// Stato di Erogazione
class DispensingState implements CoffeeMachineState {
    private $machine;

    public function __construct($machine) {
        $this->machine = $machine;
    }

    public function insertCoin() {
        echo "Attendi la fine dell'erogazione.\n";
    }

    public function pressButton() {
        echo "Attendi la fine dell'erogazione.\n";
    }

    public function dispense() {
        echo "Caffè erogato.\n";
        $this->machine->setState($this->machine->getNoCoinState());
    }
}

// Classe Macchina da Caffè
class CoffeeMachine {
    private $noCoinState;
    private $hasCoinState;
    private $dispensingState;
    private $currentState;

    public function __construct() {
        $this->noCoinState = new NoCoinState($this);
        $this->hasCoinState = new HasCoinState($this);
        $this->dispensingState = new DispensingState($this);
        $this->currentState = $this->noCoinState;
    }

    public function setState($state) {
        $this->currentState = $state;
    }

    public function insertCoin() {
        $this->currentState->insertCoin();
    }

    public function pressButton() {
        $this->currentState->pressButton();
    }

    public function dispense() {
        $this->currentState->dispense();
    }

    public function getNoCoinState() {
        return $this->noCoinState;
    }

    public function getHasCoinState() {
        return $this->hasCoinState;
    }

    public function getDispensingState() {
        return $this->dispensingState;
    }
}

// Esempio d'uso
$coffeeMachine = new CoffeeMachine();

// Interazioni con la macchina da caffè
$coffeeMachine->pressButton();  // Inserisci una moneta prima di premere il pulsante.
$coffeeMachine->insertCoin();   // Moneta inserita.
$coffeeMachine->pressButton();  // Pulsante premuto. Erogazione in corso.
$coffeeMachine->dispense();     // Caffè erogato.
$coffeeMachine->pressButton();  // Inserisci una moneta prima di premere il pulsante.

Spiegazione

  • Interfaccia CoffeeMachineState: Definisce i metodi che ogni stato della macchina dovrà implementare.
  • Stati concreti (NoCoinState, HasCoinState, DispensingState): Implementano l’interfaccia e gestiscono il comportamento della macchina a seconda dello stato.
  • Classe CoffeeMachine: Contiene una serie di stati e gestisce le transizioni tra di essi.
  • Uso della Macchina: Le transizioni tra gli stati avvengono in base alle interazioni dell’utente con la macchina, senza bisogno di gestire esplicitamente logiche condizionali complesse.

TORNA ALLA GUIDA

content_copy Copiato