javascript - Forțarea subclaselor să fie imuabile
Am o clasă de bază cu câteva proprietăți:
class Component {
readonly id: number
readonly type: number
}
Și mi-ar plăcea să am câteva subclase:
class HealthComponent extends Component {
max_health: number,
current_health: number
}
etc.
Ceea ce vreau este, în esență, ca HealthComponent să aibă același comportament ca un Immutable.Record:
const health = HealthComponent(100, 100);
health.max_health = 40; // Shouldn't work
const new_health = new HealthComponent(40, health.current_health); // Works
Toate clasele sunt doar date; nu există comportament (dacă există vreun comportament, acesta va fi în metode statice, nu în metode de instanță). Acum vreau să impun cât mai mult posibil ca subclasele să fie imuabile (în sensul că modificările sunt permise, dar efectuarea de schimbări duce la un obiect nou sau aruncă o eroare a la Immutable.js) și nu reușesc să găsesc cea mai bună modalitate de a face acest lucru.
Cel mai bun lucru la care m-am gândit este să aibă fiecare subclasă un membru data doar pentru citire, care să fie un Immutable.Record cu câmpurile corespunzătoare, dar chiar și acesta nu este tocmai corect pentru că schimbarea lui ar returna un nou obiect data, dar eu vreau cu adevărat un întreg obiect Component nou, și asta de asemenea nu impune cu adevărat ca toate componentele să urmeze această convenție.
Cealaltă chestiune pe care am luat-o în considerare este ca clasa de bază să fie un Immutable.Record cu un câmp data: Immutable.Map și apoi clasele derivate să furnizeze un Immutable.Map constructorului super cu toate cheile, dar atunci oamenii ar putea pur și simplu să adauge noi chei cum le trece prin cap, ceea ce nici asta nu este ideal.
Există un tipar de design magic care m-ar putea ajuta aici?
Răspuns #1
Folosește tipul mapat Readonly.
class Component {
constructor(public id: number, public type: number) {
}
}
class HealthComponent extends Component {
constructor(public id: number, public type: number, public max_health: number, public current_health: number) {
super(id, type);
}
}
let hc: Readonly<HealthComponent> = new HealthComponent(1, 2, 3, 4);
hc.max_health = 40; // Error
Ia în considerare folosirea unui interface dacă nu ai comportament.
interface Component {
id: number
type: number
}
interface HealthComponent extends Component {
max_health: number;
current_health: number;
}
let hc: Readonly<HealthComponent> = {
id: 1,
type: 2,
max_health: 3,
current_health: 4
};
hc.max_health = 40; // Error
