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.