Menu
Coddy logo textTech

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.

challenge icon

Sfida

Facile

Costruiamo 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'interfaccia Refuelable con 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 astratta Vehicle che fornisce funzionalità condivise a tutti i veicoli. Dovrebbe avere una proprietà protetta $brand e una proprietà protetta $fuelLevel (inizializzata a 0). Il costruttore accetta il nome della marca. Includi un metodo concreto getBrand() che restituisce la marca, un metodo concreto getFuelLevel() che restituisce il livello di carburante attuale e un metodo astratto drive() che le classi figlie devono implementare.
  • Car.php: Crea una classe Car che estende Vehicle e implementa Refuelable. Includi entrambi i file richiesti all'inizio. Il costruttore accetta la marca e la passa al costruttore della classe genitore. Implementa drive() in modo che restituisca "[brand] car is driving". Implementa refuel($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 una Car con la marca. Stampa il risultato di drive() sulla prima riga, poi stampa il risultato di refuel() 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
?>
quiz iconMettiti alla prova

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

Esercitati da solo: Compilatore PHP online