Pattern Strategy
Fa parte della sezione Programmazione orientata agli oggetti del percorso PHP di Coddy. Lezione 74 di 91.
Lo Strategy Pattern è un pattern di progettazione comportamentale che ti permette di definire una famiglia di algoritmi, incapsulare ciascuno nella propria classe e renderli intercambiabili a runtime. L'oggetto che usa la strategia non ha bisogno di sapere quale algoritmo sta eseguendo.
Immagina un carrello della spesa che può applicare diverse strategie di sconto. Invece di codificare direttamente la logica degli sconti con istruzioni condizionali, definisci ogni sconto come una classe separata:
<?php
interface DiscountStrategy {
public function calculate(float $total): float;
}
class NoDiscount implements DiscountStrategy {
public function calculate(float $total): float {
return $total;
}
}
class PercentageDiscount implements DiscountStrategy {
public function __construct(private int $percent) {}
public function calculate(float $total): float {
return $total - ($total * $this->percent / 100);
}
}
class FixedDiscount implements DiscountStrategy {
public function __construct(private float $amount) {}
public function calculate(float $total): float {
return max(0, $total - $this->amount);
}
}
La classe contesto accetta qualsiasi strategia e delega il calcolo:
<?php
class ShoppingCart {
public function __construct(private DiscountStrategy $discount) {}
public function setDiscount(DiscountStrategy $discount): void {
$this->discount = $discount;
}
public function checkout(float $total): float {
return $this->discount->calculate($total);
}
}
$cart = new ShoppingCart(new NoDiscount());
echo $cart->checkout(100) . "\n";
$cart->setDiscount(new PercentageDiscount(20));
echo $cart->checkout(100);
Output:
100
80Il pattern Strategy è ideale quando hai diversi modi per eseguire un'operazione e vuoi passare da uno all'altro senza modificare la classe che li utilizza. Aggiungere un nuovo tipo di sconto significa creare una nuova classe, senza toccare il codice esistente.
Sfida
FacileCostruiamo un calcolatore dei costi di spedizione usando lo Strategy Pattern. I diversi metodi di spedizione hanno regole di prezzo diverse: la spedizione standard applica una tariffa fissa, quella express aggiunge una percentuale e quella overnight combina entrambe. Lo Strategy Pattern ti consente di sostituire questi calcoli senza modificare il codice che li utilizza.
Organizzerai il codice in quattro file:
ShippingStrategy.php: crea un'interfacciaShippingStrategyche definisce il contratto per tutti i metodi di spedizione. Dovrebbe avere un metodocalculate(float $weight): floatche accetta il peso del pacco e restituisce il costo di spedizione.ShippingMethods.php: includi il file ShippingStrategy e crea tre classi che implementano l'interfaccia:StandardShipping: applica una tariffa fissa di$5.00indipendentemente dal pesoExpressShipping: applica un costo di$2.00per chilogrammo (moltiplica il peso per 2)OvernightShipping: applica una tariffa base di$10.00più$3.00per chilogrammo
ShippingCalculator.php: includi il file ShippingStrategy e crea una classeShippingCalculatorche funge da contesto. Il tuo calcolatore dovrebbe:- Accettare un
ShippingStrategynel costruttore (usa la promozione delle proprietà del costruttore) - Avere un metodo
setStrategy(ShippingStrategy $strategy): voidper cambiare il metodo di spedizione durante l'esecuzione - Avere un metodo
calculateCost(float $weight): floatche delega alla strategia corrente
- Accettare un
main.php: includi i file ShippingMethods e ShippingCalculator. Riceverai due input: un tipo di spedizione ("standard","express"o"overnight") e il peso di un pacco.Crea un
ShippingCalculatorche inizialmente utilizziStandardShipping. In base al tipo di spedizione inserito, usasetStrategy()per passare al metodo di spedizione appropriato. Poi calcola il costo per il peso indicato e stampa il risultato formattato con due cifre decimali.L'output dovrebbe essere:
Shipping cost: $[cost]
Questa sfida mostra come lo Strategy Pattern renda flessibile il tuo sistema di spedizione: per aggiungere un nuovo metodo di spedizione come SameDayShipping basta creare una nuova classe che implementa l'interfaccia, senza modificare il calcolatore o i metodi di spedizione esistenti.
Provalo tu
<?php
require_once 'ShippingMethods.php';
require_once 'ShippingCalculator.php';
// Leggi l'input
$shippingType = trim(fgets(STDIN));
$weight = floatval(fgets(STDIN));
// TODO: Crea un ShippingCalculator iniziando con StandardShipping
// TODO: In base al tipo di spedizione inserito ("standard", "express" o "overnight"),
// usa setStrategy() per passare al metodo di spedizione appropriato
// TODO: Calcola il costo per il peso indicato
// TODO: Stampa il risultato formattato con due cifre decimali
// Formato dell'output: Shipping cost: $[cost]
?>Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniIntroduzione alla programmazione orientata agli oggettiClassi e oggettiLa parola chiave $thisMetodiProprietàCostruttore (__construct)Distruttore (__destruct)Riepilogo - Calcolatrice semplice4Ereditarietà
Ereditarietà di baseLa parola chiave parent::Sovrascrittura dei metodiLa parola chiave finalClassi astratteRiepilogo - Gerarchia dei dipendenti7Incapsulamento
Pubblico, Protetto, PrivatoApprofondimento sui modificatori di accessoGetter e SetterOccultamento delle informazioniPromozione dei parametri del costruttore (8.0)Riepilogo - Sistema di gestione dei registri degli studenti10Concetti avanzati di programmazione a oggetti
Composizione vs ereditarietàDependency InjectionClassi anonimeEnumerazioni (PHP 8.1)Fibers (PHP 8.1)Approfondimento sulla clonazione degli oggettiGeneratori e iteratori13Modelli di progettazione, parte 2
Modello CommandModello AdapterModello DecoratorModello Template MethodModello StateModello CompositeModello Repository2Namespace e autoloading
Introduzione ai namespaceLa keyword useStandard di autoloading PSR-4Autoloader di ComposerRiepilogo - Progetto organizzato5Interfacce e contratti
Introduzione alle interfacceImplementare le interfacceImplementare più interfacceInterfaccia vs classe astrattaType hinting con le interfacceRiepilogo - Calcolatore di forme8Metodi magici
Introduzione ai metodi magici__toString e __debugInfo__get, __set, __isset, __unset__call e __callStatic__clone e clonazione degli oggetti__serialize e __unserializeRiepilogo - Collezione personalizzata11Sistema dei tipi e gestione degli errori
Dichiarazioni di tipoTipi nullableTipi unione e intersezioneClassi di eccezioneGerarchia di eccezioni personalizzataTry, Catch, FinallyRiepilogo - Validatore di moduli14Progetto: Gestione della biblioteca
Panoramica del progettoClassi Libro e Utente3Proprietà delle classi
Proprietà di istanza e staticheCostanti nelle classiMetodi e proprietà staticiProprietà private e protectedProprietà readonly (PHP 8.1)Riepilogo - Gestore di conti bancari6Polimorfismo
Ridefinizione dei metodi, ripresaPolimorfismo tramite interfacceSuggerimenti sui tipi e tipi UnionBinding statico tardivoRiepilogo - Processore di pagamenti9Tratti
Introduzione ai trattiUtilizzare più trattiRisoluzione dei conflitti tra trattiMetodi astratti nei trattiTratti vs ereditarietà12Design pattern - Parte 1
Introduzione ai design patternPattern SingletonPattern FactoryPattern ObserverPattern StrategyEsercitati da solo: Compilatore PHP online