Design patterns: Strategy
Lo Strategy Pattern è un pattern comportamentale che consente di definire una famiglia di algoritmi, incapsularli in classi separate e renderli intercambiabili tra loro. L’algoritmo da utilizzare può essere selezionato dinamicamente a runtime, rendendo il codice più flessibile e facilmente estendibile. Questo pattern è particolarmente utile quando si desidera evitare lunghi blocchi condizionali (come if-else
o switch-case
) per scegliere tra diversi algoritmi.
Punti di Forza
- Separazione del codice: Ogni algoritmo è incapsulato nella propria classe, separando la logica dell’algoritmo dal contesto in cui viene usato.
- Intercambiabilità degli algoritmi: Gli algoritmi possono essere cambiati a runtime senza modificare il codice del client.
- Aumento della manutenibilità: Aggiungere o modificare algoritmi non impatta il resto del codice.
- Estensibilità: È facile aggiungere nuovi algoritmi implementando semplicemente una nuova classe che segue la stessa interfaccia.
- Favorisce la coesione: Il contesto gestisce solo la logica di alto livello, mentre le strategie si occupano dell’implementazione specifica degli algoritmi.
Caso d’uso: Sistema di pagamento
Immagina un sistema di pagamento che supporta diversi metodi: Carta di Credito, PayPal e Bonifico Bancario. A seconda del metodo di pagamento scelto dall’utente, l’algoritmo per processare il pagamento cambia.
Codice PHP
<?php
// Interfaccia Strategia di pagamento
interface PaymentStrategy {
public function pay($amount);
}
// Strategia pagamento con Carta di Credito
class CreditCardPayment implements PaymentStrategy {
private $cardNumber;
public function __construct($cardNumber) {
$this->cardNumber = $cardNumber;
}
public function pay($amount) {
echo "Pagamento di $amount effettuato con Carta di Credito numero: {$this->cardNumber}.\n";
}
}
// Strategia pagamento con PayPal
class PayPalPayment implements PaymentStrategy {
private $email;
public function __construct($email) {
$this->email = $email;
}
public function pay($amount) {
echo "Pagamento di $amount effettuato con PayPal all'indirizzo: {$this->email}.\n";
}
}
// Strategia pagamento con Bonifico Bancario
class BankTransferPayment implements PaymentStrategy {
private $bankAccount;
public function __construct($bankAccount) {
$this->bankAccount = $bankAccount;
}
public function pay($amount) {
echo "Pagamento di $amount effettuato tramite Bonifico Bancario sul conto: {$this->bankAccount}.\n";
}
}
// Classe Contesto per il pagamento
class PaymentContext {
private $paymentStrategy;
public function __construct(PaymentStrategy $paymentStrategy) {
$this->paymentStrategy = $paymentStrategy;
}
public function setPaymentStrategy(PaymentStrategy $paymentStrategy) {
$this->paymentStrategy = $paymentStrategy;
}
public function pay($amount) {
$this->paymentStrategy->pay($amount);
}
}
// Esempio d'uso
$context = new PaymentContext(new CreditCardPayment("1234-5678-9876-5432"));
$context->pay(100); // Pagamento con Carta di Credito
$context->setPaymentStrategy(new PayPalPayment("user@example.com"));
$context->pay(200); // Pagamento con PayPal
$context->setPaymentStrategy(new BankTransferPayment("IT60X0542811101000000123456"));
$context->pay(300); // Pagamento con Bonifico Bancario
Spiegazione
- Interfaccia PaymentStrategy: Definisce il metodo pay(), che ogni strategia di pagamento deve implementare.
- Strategie Concrete (CreditCardPayment, PayPalPayment, BankTransferPayment): Implementano l’interfaccia e gestiscono l’algoritmo di pagamento per il rispettivo metodo.
- Classe PaymentContext: Gestisce l’algoritmo di pagamento corrente e permette di cambiare strategia a runtime.
- Uso del contesto: L’utente può cambiare il metodo di pagamento senza modificare il contesto stesso; la strategia viene semplicemente sostituita.
Conclusione
Lo Strategy Pattern separa chiaramente gli algoritmi dal contesto in cui sono utilizzati, migliorando la modularità e permettendo l’intercambiabilità degli algoritmi a runtime. Questo è particolarmente utile in sistemi complessi che richiedono una varietà di algoritmi o logiche.