Interfaccia o classe astratta
Fa parte della sezione Programmazione orientata agli oggetti del percorso C# di Coddy. Lezione 26 di 70.
Sia le interfacce che le classi astratte ti permettono di definire contratti che le altre classi devono rispettare, ma hanno scopi diversi e funzionalità distinte.
Un'interfaccia definisce cosa deve fare una classe, senza alcuna implementazione. È un puro contratto:
public interface IFlyable
{
void Fly();
}
public class Bird : IFlyable
{
public void Fly()
{
Console.WriteLine("Flapping wings");
}
}Una classe astratta può fornire sia un contratto sia un’implementazione condivisa. È un progetto parziale:
public abstract class Vehicle
{
public string Brand { get; set; }
public void StartEngine()
{
Console.WriteLine("Engine started");
}
public abstract void Drive(); // Deve essere implementato
}
public class Car : Vehicle
{
public override void Drive()
{
Console.WriteLine("Driving on roads");
}
}Le differenze principali riguardano le regole di ereditarietà e lo scopo.
Una classe può implementare più interfacce, ma ereditare da una sola classe astratta.
Usa un'interfaccia quando classi non correlate devono condividere un comportamento (come IFlyable per gli uccelli e gli aerei). Usa una classe astratta quando classi correlate condividono codice e stato comuni (come i veicoli che condividono un meccanismo di avviamento del motore).
Le classi astratte possono avere costruttori, campi e modificatori di accesso sui membri. Tradizionalmente, le interfacce non potevano averli, anche se le versioni moderne di C# consentono implementazioni predefinite.
In caso di dubbio, preferisci le interfacce per una maggiore flessibilità: potrai sempre aggiungere in seguito una classe astratta se diventa necessaria un'implementazione condivisa.
Sfida
FacileCostruiamo un sistema di lettore multimediale che mostri quando usare le interfacce invece delle classi astratte. Creerai una struttura in cui dispositivi non correlati condividono il comportamento di riproduzione tramite un’interfaccia, mentre tipi di contenuti multimediali correlati condividono un’implementazione comune tramite una classe astratta.
Organizzerai il codice in quattro file:
IPlayable.cs: Definisci un’interfaccia chiamataIPlayablenello spazio dei nomiMedia. Questa interfaccia rappresenta il contratto per qualsiasi elemento in grado di riprodurre contenuti multimediali: che si tratti di un telefono, di una TV o di un lettore musicale dedicato. Deve dichiarare un unico metodoPlay()che restituisce una stringa.MediaFile.cs: Definisci una classe astratta chiamataMediaFilenello spazio dei nomiMedia. Rappresenta la base condivisa per tutti i file multimediali. Deve avere una proprietàTitle(string) e una proprietàDuration(int, che rappresenta i secondi). Includi un costruttore che imposti entrambi i valori. Aggiungi un metodo concreto chiamatoGetInfo()che restituisce"{Title} ({Duration}s)". Dichiara anche un metodo astrattoGetType()che restituisce una stringa: ogni tipo di contenuto multimediale definirà quale tipo di file rappresenta.AudioFile.cs: Definisci una classeAudioFilenello spazio dei nomiMediache eredita daMediaFilee implementaIPlayable. Aggiungi una proprietàArtist(string). Il costruttore deve accettare titolo, durata e artista. Esegui l’override diGetType()affinché restituisca"Audio". ImplementaPlay()affinché restituisca"Playing audio: {Title} by {Artist}".Program.cs: Nel file principale, crea unAudioFileusando i valori di input. Mostra entrambi gli aspetti della classe: chiamaGetInfo()eGetType()(ereditati dalla classe astratta), quindi chiamaPlay()(dall’interfaccia). Assegna il file audio a una variabileIPlayablee chiama di nuovoPlay()per mostrare il polimorfismo dell’interfaccia.
Riceverai tre input:
- Titolo del brano
- Durata in secondi
- Nome dell’artista
Stampa l’output in questo formato:
Info: {GetInfo() result}
Type: {GetType() result}
Direct: {Play() result}
Via Interface: {Play() result from IPlayable variable}Per esempio, se gli input sono Bohemian Rhapsody, 354 e Queen, l’output dovrebbe essere:
Info: Bohemian Rhapsody (354s)
Type: Audio
Direct: Playing audio: Bohemian Rhapsody by Queen
Via Interface: Playing audio: Bohemian Rhapsody by QueenNota come AudioFile tragga vantaggio da entrambi gli approcci: eredita l’implementazione condivisa (GetInfo()) dalla classe astratta e al tempo stesso soddisfa il contratto IPlayable. La classe astratta consente il riutilizzo del codice per tipi di contenuti multimediali correlati, mentre l’interfaccia permette a qualsiasi classe non correlata di essere «riproducibile» senza condividere una gerarchia di ereditarietà.
Provalo tu
using System;
using Media;
class Program
{
public static void Main(string[] args)
{
// Leggi i valori di input
string title = Console.ReadLine();
int duration = Convert.ToInt32(Console.ReadLine());
string artist = Console.ReadLine();
// TODO: Crea un AudioFile usando i valori di input
// TODO: Stampa Info: seguito dal risultato di GetInfo()
// TODO: Stampa Type: seguito dal risultato di GetType()
// TODO: Stampa Direct: seguito dal risultato di Play()
// TODO: Memorizza il file audio in una variabile IPlayable
// TODO: Stampa Via Interface: seguito dal risultato di Play() della variabile IPlayable
}
}
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 esterniNamespace e direttiveIntroduzione a classi e oggettiLa parola chiave "this"Metodi e parametriCampi e proprietàCostruttoriInizializzatori di oggettiRiepilogo - Calcolatrice semplice4Ereditarietà
Sintassi di base dell'ereditarietà (:)La parola chiave 'base'Parole chiave virtual e overrideClassi sealedLa classe base 'object'Riepilogo - Gerarchia dei dipendenti7Funzionalità avanzate
Sovraccarico degli operatoriIndicizzatori (this[])Override di ToString()Metodi di estensioneRiepilogo - Lista personalizzata10Pattern di progettazione Parte 1
Introduzione ai pattern di progettazioneSingleton thread-safePattern FactoryPattern Observer (eventi)Pattern Strategy2Proprietà e membri statici
Proprietà implementate automaticamenteProprietà di sola lettura e di sola scritturaCampi e metodi staticiClassi staticheMembri con corpo di espressione5Polimorfismo e interfacce
Polimorfismo a compile time e runtimeInterfaccia o classe astrattaInterfacce multipleInterfacce espliciteUpcasting e downcastingRipasso: calcolatore di forme8Concetti avanzati di programmazione a oggetti
Composizione invece dell'ereditarietàTipi generici (classi e metodi)Delegati ed eventiAttributi e reflectionIDisposable e istruzione usingNozioni di base sull'iniezione delle dipendenze11Pattern di progettazione, parte 2
Pattern del ComandoPattern dell’AdattatorePattern del DecoratorePattern Template MethodPattern dello StatoPattern Composito3Architettura delle classi
Dati di istanza vs staticiParole chiave 'readonly' e 'const'Campi di supportoRiepilogo - Gestore di conti bancari6Incapsulamento
Modificatori di accessoProprietà per l'incapsulamentoImplementazione dell'occultamento dei datiModelli di immutabilitàRiepilogo - Registri degli studentiEsercitati da solo: Compilatore C# online