Dies ist ein Fall von:
- Methoden, die zu viel zu tun Weg
- Ein Mangel an
super
- tief verschachtelte Hierarchien eine schmerzhafte Art und Weise des Schreibens wartbaren Systeme sind auf Verfahren zur rufend; multipliziert mit 4000x in JS
Erstens: Jetzt
// assume
class A extends Array {
doX (x) {
console.log(`A.doX(${x})`);
return new A();
}
}
class B extends A {
doX (x, y) {
super.doX(x);
console.log(`B.doX(${x}, ${y})`);
return new B();
}
}
class C extends B {
doX (x, y, z) {
super.doX(x, y);
console.log(`C.doX(${x}, ${y}, ${z})`);
return new C();
}
}
const c = new C();
c.doX(1, 2, 3);
// "A.doX(1)"
// "B.doX(1, 2)"
// "C.doX(1, 2, 3)"
, sollte ich erwarten keine Probleme zu haben, was auch immer diesen Code ausgeführt wird.
Ich werde eine Hölle von Zeit wirklich nutzen, obwohl es.
Warum? Weil ich die Entscheidung getroffen habe, die Methode zu überladen, um gleichzeitig um Konstruktion und Logik zu sorgen.
Die A-Klasse gibt immer ein A zurück, die B-Klasse gibt immer ein B zurück, obwohl der Superaufruf tatsächlich ein völlig anderes Objekt (ein neues A) zurückgibt. Das C gibt ein neues C zurück, obwohl es bereits ein A und ein B erzeugt hat (hat aber keinen Bezug auf A).
Also was machst du?
Ein paar Gedanken:
- den Bau des Objekts bewegen Weise das Heck aus dem Objekt, und es passieren, statt
- Trennen Sie Ihre Datenobjekt aus Ihrer Bibliothek
Also lassen Sie uns Bau Trennung versuchen
class Person {
static make() { return new Person(); }
setDetails (name, age) {
this.name = name;
this.age = age;
}
clone (cfg = this) {
const person = Person.make();
person.setDetails(cfg.name, cfg.age);
return person;
}
}
class Employee extends Person {
static make() { return new Employee(); }
setDetails (name, age, id) {
super.setDetails(name, age);
this.id = id;
}
clone (cfg = this) {
const employee = Employee.make();
employee.setDetails(cfg.name, cfg.age, cfg.id);
return employee;
}
}
Sie werden feststellen, dass die Methoden clone
nicht vererbt werden. Sie konzentrieren sich auf Instanziierung. Sie sind im Grunde Fabriken (das ist wirklich der Bereich eines separaten Objekts oder eine statische Methode, wie make|from|of|empty|unit
).
Dann rufen sie setDetails
an, was eine Instanzmethode ist, die im Grunde tut, was der Konstruktor hätte tun sollen oder was eine Fabrik tun sollte, und hat geerbtes Verhalten.
Apropos DRY, Erbschaft ist eine Art schrecklicher Weg, um so zu bleiben. Nur aus dem, was ich geschrieben habe, wie viele Zeilen wurden entweder zum Überschreiben von Konstruktoren (clone
, make
), oder Aufruf an Eltern (super
) oder auch nur über die Erweiterung, nur weil gerade besorgt?
Das bringt mich zu einem anderen Muster: Bibliotheken, reine Funktionen/Methoden und Dekoration.
Wenn Sie sich nicht um den eigentlichen "Typ" kümmern (und in rohen JS, während in der Konsole hilfreich, sollten Sie nicht, weil es woanders nutzlos ist), dann können Sie glücklich datenzentrische Objekte machen.
Structs, genau wie Sie in C oder Go oder Python oder dergleichen sehen würden.
Dann könnten Sie alle wiederverwendbaren Berechnungen schreiben, die Sie möglicherweise für Bibliotheken/Dienste wünschen, die Sie für diese Strukturen (oder idealerweise Kopien davon) verwenden.
class Vector {
static make2D (x = 0, y = 0) {
return { x, y };
}
static make3D (x = 0, y = 0, z = 0) {
return { ...Vector.make2D(x, y), z };
}
static add2D (v1, v2) {
return Vector.make2D(v1.x + v2.x, v1.y + v2.y);
}
}
const vectors = [
{ x: 0, y: 1 },
{ x: 32, y: 8 },
{ x: 10, y: 12 },
{ x: 0, y: 0 },
];
const vectorSum = vectors.reduce(Vector.add2D, Vector.make2D());
vectorSum; // { x: 42, y: 21 }
Wenn Sie benötigt sie wirklich eingegeben haben, werden dann so etwas wie Sie tun können:
class Vector {
add2D (
{x: x1, y: y1},
{x: x2, y: y2}
) {
return Vector2D.of(x1 + x2, y1 + y2);
}
}
class Vector2D {
constructor (x, y) {
return Object.assign(this, { x, y });
}
static of (x, y) { return new Vector2D(x, y); }
static from ({ x, y }) { return Vector2D.of(x, y); }
static empty() { return Vector2D.of(0, 0); }
}
const vector = vectors
.map(Vector2D.from)
.reduce(Vector.add2D, Vector2D.empty());
// Vector2D { x: 42, y: 21 }
Sie würden eine harte Zeit, über Ihren Code zu diesem Zeitpunkt nicht trocken sein beschwert haben. Sie könnten sogar 5D-Vektoren in die Eingabedaten einfügen, und Sie würden korrekte 2D-Vektoren erhalten ...