Design patterns: Bridge
Il Bridge Pattern separa l’astrazione dall’implementazione, consentendo loro di variare indipendentemente. Questo pattern è utile quando si vuole evitare un’esplosione di classi derivate dovuta a più dimensioni di variazioni.
Caratteristiche del Bridge pattern
- Separazione tra astrazione e implementazione: Il Bridge Pattern separa l’astrazione (interfaccia o logica di alto livello) dall’implementazione (dettagli concreti), permettendo loro di variare indipendentemente.
- Flessibilità ed estensibilità: Favorisce l’estensibilità, consentendo di aggiungere nuove astrazioni e implementazioni senza modificare il codice esistente. Questo rende il sistema più flessibile e facilmente adattabile a nuovi requisiti.
- Riduzione della complessità: Riduce il numero di classi necessarie rispetto all’approccio tradizionale, evitando la proliferazione di classi derivate. Permette di combinare diverse astrazioni e implementazioni senza creare gerarchie multiple.
- Supporto per l’Indipendenza delle componenti: L’astrazione non dipende dall’implementazione, e viceversa. Ciò significa che è possibile modificare l’implementazione senza influenzare l’astrazione e viceversa, mantenendo le due componenti indipendenti.
- Migliore manutenibilità: La separazione delle responsabilità tra astrazione e implementazione facilita la manutenzione del codice. Le modifiche possono essere fatte in una parte senza influenzare l’altra, riducendo il rischio di introdurre errori.
- Combinazioni dinamiche: Consente di creare dinamicamente combinazioni tra astrazioni e implementazioni diverse durante il runtime, migliorando la flessibilità operativa.
- Utilizzo in sistemi con multiple piattaforme: Il Bridge Pattern è particolarmente utile quando un sistema deve supportare più piattaforme, poiché consente di mantenere una singola interfaccia astratta che può funzionare con diverse implementazioni specifiche per ogni piattaforma.
- Riduzione del coupling (accoppiamento): Promuove un basso accoppiamento tra le classi, poiché l’astrazione e l’implementazione sono completamente separate. Questo riduce la dipendenza diretta tra componenti.
Esempio in PHP:
Immaginiamo di voler rappresentare diversi strumenti di pagamento (es. Carta di Credito e PayPal) per diversi tipi di account (es. Personale e Business). Il Bridge Pattern ci permette di separare i metodi di pagamento dagli account, consentendo di avere combinazioni flessibili senza dover creare una classe per ogni combinazione di account e metodo di pagamento.
// Implementazione: Interfaccia per i metodi di pagamento
interface PaymentMethod {
public function processPayment($amount);
}
// Implementazione concreta: Carta di Credito
class CreditCard implements PaymentMethod {
public function processPayment($amount) {
echo "Pagamento di $amount processato tramite Carta di Credito.\n";
}
}
// Implementazione concreta: PayPal
class PayPal implements PaymentMethod {
public function processPayment($amount) {
echo "Pagamento di $amount processato tramite PayPal.\n";
}
}
// Abstraction: l'Account
abstract class Account {
protected $paymentMethod;
public function __construct(PaymentMethod $paymentMethod) {
$this->paymentMethod = $paymentMethod;
}
abstract public function makePayment($amount);
}
// Refined Abstraction: Account Personale
class PersonalAccount extends Account {
public function makePayment($amount) {
echo "Account Personale: ";
$this->paymentMethod->processPayment($amount);
}
}
// Refined Abstraction: Account Business
class BusinessAccount extends Account {
public function makePayment($amount) {
echo "Account Business: ";
$this->paymentMethod->processPayment($amount);
}
}
// Utilizzo
$personalAccountWithCreditCard = new PersonalAccount(new CreditCard());
$personalAccountWithCreditCard->makePayment(100); // Output: Account Personale: Pagamento di 100 processato tramite Carta di Credito.
$businessAccountWithPayPal = new BusinessAccount(new PayPal());
$businessAccountWithPayPal->makePayment(250); // Output: Account Business: Pagamento di 250 processato tramite PayPal.