78 TS – Classi astratte vs Interfaccie
Una classe astratta è una classe che implementa lo scheletro strutturale di un metodo, ma lascia il compito di ultimare e implementare questo metodo alle classi che la estendono.
Le classi figlie avranno obbligatoriamente i metodi stanziati nella classe astratta dalla quale discendono e avranno il compito di ultimare tali metodi.
Per definire una classe astratta è necessario utilizzare la keyword abstract prima dell’attributo class e definiamo il metodo astratto che vogliamo implementare nelle classi discendenti.
abstract class Logger { abstract log(msg : string) : void; }
In presenza di un metodo abstract definirò necessariamente anche la classe come abstract.
La classe astratta può tranquillamente avere metodi interni non astratti
abstract class Logger { abstract log(msg : string) : void generateId() : number { return Math.round(Math.random()*1000000); } }
La classe astratta non può essere stanziata direttamente da un oggetto, ma deve essere estesa da una classe discendente
class ConsolLogger extends Logger { }
Già l’editor ci avvisa che essendo un’estensione di una classe astratta, deve obbligatoriamente implementare gli stessi metodi astratti
abstract class Logger { abstract log(msg : string) : void generateId() : number { return Math.round(Math.random()*1000000); } } class ConsolLogger extends Logger { log(msg: string): void { } } let log = new ConsolLogger();
In questo caso, nonostante non abbia un risultato, abbiamo implementato una struttura corretta del codice, perchè abbiamo definito classe e metodo astratto, abbiamo definito la classe che li estende, abbiamo definito un oggetto costruito sulla classe concreta estensione di quella astratta.
Aggiungiamo dei console nel metodo e nell’oggetto per testare
abstract class Logger { abstract log(msg : string) : void generateId() : number { return Math.round(Math.random()*1000000); } } class ConsolLogger extends Logger { log(msg: string): void { console.log(msg); } } let Clog = new ConsolLogger(); Clog.log('login to console');
L’oggetto come la classe reale ha accesso automaticamente anche al metodo concreto della classe astratta
console.log(Clog.generateId());
Quindi quando usare una classe astratta e quando un’interfaccia?
Un’ interface ci serve solo quando dobbiamo stabilire le proprietà e i metodi che una classe deve avere senza alcuna implementazione.
La classe abstract può avere metodi già implementati e lasciare la loro definizione particolare alla classe discendente.
Ovviamente una classe può estendere una classe astratta ed implementare anche un’interface:
interface Log { msg: string id: number }
ora estendiamo la classe astratta ed implementiamo Log
class ConsolLogger extends Logger implements Log { msg : string = ''; id : number = 0; log(msg: string): void { console.log(msg); } }
volendo potremmo anche creare un costruttore che inizializza queste proprietà .
Possiamo inserire anche un metodo nell’interfaccia, ma non completalo
interface Log { msg: string; id: number; getMsg() : string; ShowMsg() : string { console.log(this.msg); } }
Errore ShowMsg non può avere risultati in un’interfaccia, mentre getMsg() è corretto perchè solo dichiarato, quindi lo implemento e risolvo nella classe figlia
class ConsolLogger extends Logger implements Log { msg : string = ''; id : number = 0; log(msg: string): void { console.log(msg); } getMsg(): string { return this.msg(); } }
Riassumendo
Nella classe abstract posso definire ed implementare metodi, nell’interfaccia posso solo creare lo schema definendo solo nomi e tipi di proprietà e metodi.