Interfaccia vs classe astratta
Fa parte della sezione Programmazione orientata agli oggetti del percorso PHP di Coddy. Lezione 30 di 91.
Ora che hai imparato sia le interfacce sia le classi astratte, chiariamo quando usare ciascuna. Anche se possono sembrare simili, hanno scopi diversi e capacità distinte.
| Caratteristica | Interfaccia | Classe astratta |
|---|---|---|
| Metodi | Solo firme dei metodi | Sia metodi astratti che concreti |
| Proprietà | Solo costanti | Può avere proprietà |
| Ereditarietà multipla | Una classe può implementarne molte | Una classe può estenderne solo una |
| Costruttore | Può dichiarare una firma __construct (senza corpo) | Può definire un costruttore con un corpo |
Usa un’interfaccia quando vuoi definire un contratto che classi non correlate possono rispettare. Per esempio, sia una Printer sia un Logger potrebbero implementare un’interfaccia Writable, anche se non condividono alcun antenato comune.
Usa una classe astratta quando hai classi correlate che condividono codice comune. Se le tue classi Dog e Cat hanno entrambe bisogno della stessa implementazione del metodo eat(), una classe astratta Animal ti permette di scrivere quel codice una sola volta.
Puoi anche combinare entrambi gli approcci. Una classe può estendere una classe astratta e implementare più interfacce:
<?php
abstract class Animal {
protected $name;
public function eat() {
return $this->name . " is eating";
}
}
interface Swimmable {
public function swim();
}
class Duck extends Animal implements Swimmable {
public function __construct($name) {
$this->name = $name;
}
public function swim() {
return $this->name . " is swimming";
}
}
Punto chiave: Scegli le interfacce per definire capacità tra classi non correlate. Scegli le classi astratte quando devi condividere codice tra classi correlate.
Sfida
FacileCostruiamo un sistema di veicoli che mostri quando usare una classe astratta invece di un'interfaccia e come combinare efficacemente entrambi gli approcci.
Creerai un sistema in cui i veicoli condividono proprietà comuni tramite l'ereditarietà, ma possono anche acquisire capacità aggiuntive tramite le interfacce. Questo rispecchia le decisioni di progettazione del mondo reale: un'auto "è un" veicolo (ereditarietà), ma ha anche "la capacità" di poter essere rifornita (interfaccia).
Organizza il codice in quattro file:
Refuelable.php: Definisci un'interfacciaRefuelablecon una sola firma di metodo:refuel($amount). Questa capacità può essere applicata a qualsiasi classe che necessiti di rifornimento, indipendentemente dalla sua gerarchia di ereditarietà.Vehicle.php: Definisci una classe astrattaVehicleche fornisce funzionalità condivise a tutti i veicoli. Dovrebbe avere una proprietà protetta$brande una proprietà protetta$fuelLevel(inizializzata a 0). Il costruttore accetta il nome della marca. Includi un metodo concretogetBrand()che restituisce la marca, un metodo concretogetFuelLevel()che restituisce il livello di carburante attuale e un metodo astrattodrive()che le classi figlie devono implementare.Car.php: Crea una classeCarche estendeVehiclee implementaRefuelable. Includi entrambi i file richiesti all'inizio. Il costruttore accetta la marca e la passa al costruttore della classe genitore. Implementadrive()in modo che restituisca"[brand] car is driving". Implementarefuel($amount)in modo che aggiunga l'importo al livello di carburante e restituisca"[brand] refueled to [fuelLevel] liters".main.php: Includi il file Car. Riceverai due input: il nome di una marca e una quantità di carburante (da convertire in intero). Crea unaCarcon la marca. Stampa il risultato didrive()sulla prima riga, poi stampa il risultato direfuel()con la quantità di carburante sulla seconda riga.
Questa sfida illustra la distinzione fondamentale: la classe astratta Vehicle condivide codice e stabilisce una relazione "è un", mentre l'interfaccia Refuelable aggiunge una capacità che potrebbe applicarsi ad altre classi non correlate (come un generatore o una barca) senza richiedere che siano veicoli.
Provalo tu
<?php
require_once 'Car.php';
// Leggi l'input
$brand = trim(fgets(STDIN));
$fuelAmount = intval(trim(fgets(STDIN)));
// TODO: Crea un Car con la marca
// TODO: Stampa il risultato di drive() sulla prima riga
// TODO: Stampa il risultato di refuel() con la quantità di carburante sulla seconda riga
?>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