Interfețe mici
Principiul Segregării Interfețelor spune: niciun tip nu ar trebui să fie obligat să implementeze metode de care nu are nevoie. În loc de o interfață supraîncărcată cu multe metode, fă mai multe interfețe mici — fiecare tip implementează doar ceea ce este adevărat pentru el.
TypeScript face interfețele mici ieftine: tipurile se potrivesc cu o interfață după formă, așa că o clasă satisface o interfață cu o singură metodă doar prin faptul că are acea metodă. Poți defini o interfață minusculă exact pentru ce îi trebuie funcției tale, iar orice valoare care i se potrivește se califică deja.
Interfața supraîncărcată
O interfață Worker cu work() și eat() pare inofensivă — până când un robot își depune candidatura pentru post. Robotul lucrează bine, dar trebuie să implementeze și eat(), cu... ceva. Răspunsurile fără sens ca acesta sunt semnătura unei interfețe supraîncărcate.
Robotul obligat să mănânce
Robotul implementează eat() doar pentru că interfața o cere. Pauza de masă afișează un răspuns care nu ar trebui să existe niciodată — clasa a fost obligată să mintă.
Ieșire: program TypeScript și rezultatul capturat
// O singură interfață supraîncărcată — orice muncitor TREBUIE să și mănânce.
interface Worker {
work(): string
eat(): string
}
class Human implements Worker {
work(): string {
return "om: lucrează"
}
eat(): string {
return "om: mănâncă prânzul"
}
}
class Robot implements Worker {
work(): string {
return "robot: lucrează"
}
// Impusă de interfață — roboții nu mănâncă.
eat(): string {
return "robot: EROARE, nu poate mânca"
}
}
const team: Worker[] = [new Human(), new Robot()]
for (const w of team) {
console.log(w.work())
}
for (const w of team) {
console.log(w.eat())
}
Împarte interfața
Împarte interfața supraîncărcată în Worker și Eater. Omul le implementează pe amândouă; robotul implementează doar Worker. Schimbul de lucru primește muncitori, pauza de masă primește mâncători — robotul pur și simplu nu este invitat niciodată la masă și nicio metodă nu minte.
Fiecare tip implementează doar adevărul său
Două interfețe mici în loc de una supraîncărcată. Robotul nu mai are deloc o metodă eat() — verificatorul de tipuri îl ține automat în afara pauzei de masă.
Ieșire: program TypeScript și rezultatul capturat
// Două interfețe mici — fiecare clasă implementează doar ce este adevărat pentru ea.
interface Worker {
work(): string
}
interface Eater {
eat(): string
}
class Human implements Worker, Eater {
work(): string {
return "om: lucrează"
}
eat(): string {
return "om: mănâncă prânzul"
}
}
class Robot implements Worker {
work(): string {
return "robot: lucrează"
}
}
function workShift(team: Worker[]): void {
for (const w of team) {
console.log(w.work())
}
}
function lunchBreak(guests: Eater[]): void {
for (const e of guests) {
console.log(e.eat())
}
}
workShift([new Human(), new Robot()])
lunchBreak([new Human()])
Piesele mici se compun
Interfețele mici nu sunt o limitare — ele se combină. Când o funcție chiar are nevoie de ambele capacități, le compune pe loc într-o singură interfață: Worker plus Eater.
Acesta este modelul spre care să țintești: definește interfețe mici și lasă-l pe cel care are nevoie de mai mult să le lipească împreună cu extends.
Compune atunci când ai nevoie de amândouă
WorkingEater este construită din cele două interfețe mici. Schimbul de o zi întreagă are nevoie de ambele capacități, așa că doar omul se califică — spus o singură dată, în sistemul de tipuri.
Ieșire: program TypeScript și rezultatul capturat
interface Worker {
work(): string
}
interface Eater {
eat(): string
}
// Interfețele mici se compun în altele mai mari atunci când este nevoie.
interface WorkingEater extends Worker, Eater {}
class Human implements WorkingEater {
work(): string {
return "om: lucrează"
}
eat(): string {
return "om: mănâncă prânzul"
}
}
function fullDay(we: WorkingEater): void {
console.log(we.work())
console.log(we.eat())
console.log(we.work())
}
fullDay(new Human())