Implementierung einer Reihe spezifischer Werte im Vergleich zur Verwendung einer Art generischer Menge mit erweiterten Überprüfungen

8

Ich arbeite derzeit an einer Set-Implementierung in JavaScript. Dies sollte Generika simulieren, wie sie aus Java oder C # bekannt sind. Ich benötige eine veränderbare Version davon (ermöglicht das Hinzufügen / Entfernen von festgelegten Werten) und eine unveränderliche.

Meine Konstruktorsignatur sieht folgendermaßen aus:

new GenericSet( 'number', [ 10, 20, 30 ] );

,

 // mutable set of mixed values (allows to add further values via "add")
 new MutableGenericSet( '*', [ 'foo', 42, {}, /./ ] );

oder

// DataValues.prototype.equals will be used by the set for determining equality.
new GenericSet( { type: DataValue, valueComparison: 'equals' }, [ dv1, dv2, dv3 ] );

Nur GenericSet oder eine Set-Implementierung pro Typ?

Anfangs bestand mein Hauptzweck darin, Wertesätze eines Typs zu haben. ZB ein DataValuesSet, das nur Datenwerte akzeptiert. Ich könnte dann Schnittstellen mit Funktionen definieren, die eine DataValuesSet- Instanz erfordern . Ich konnte keine Vererbung verwenden (und denke, das wäre sowieso schlecht), also würde ich Komposition verwenden und intern eine GenericSet / MutableGenericSet- Instanz haben.

Ein alternativer Ansatz wäre, immer GenericSet zu nehmen und zu implementieren und zu verwenden, GenericSet.requireSetOfType( type )was einen Fehler auslösen würde, wenn der Typ des Sets nicht der erforderliche wäre. Mein Anliegen dabei ist, dass meine Schnittstellendefinitionen weniger explizit aussehen.

Nehmen

/**
 * @param DataValuesSet dataValues
 */
function printDataValues( dataValues ) {
    if( !( dataValues instanceof DataValuesSet ) ) {
        throw Error( '...' );
    }
    // ...
}

vs.

/**
 * @param GenericSet<DataValue>
 */
function printDataValues( dataValues ) {
    // Throws error if dataValues is not a set or it it is a set with values of wrong type.
    GenericSet.requireSetOfType( dataValues, DataValue );
    // ...
}

Vielleicht @param GenericSet(DataValues) dataValueswäre es in Ordnung, die zweite Wahl zu dokumentieren. Hat jemand weitere Auswirkungen auf den zweiten Ansatz oder gibt es alternative Vorschläge? Für mich sieht der zweite intuitiver aus und mein Anliegen beim ersten ist, dass ich mit Konstruktoren nur mehr Overhead schaffen würde, während ich momentan keinen klaren Vorteil sehe.

Daniel AR Werner
quelle
6
Warum sollten Generika in einer Sprache wie JS wichtig sein, die schwach typisiert ist?
Yazad
1
Dies ist in einer Sprache wie JavaScript, die sowohl schwach als auch dynamisch typisiert ist, nicht möglich. Verwenden Sie einfach eine typisierte JS-Variante wie TypeScript.
Gardenhead

Antworten:

3

Ich habe versucht, diese Art von Problemen mit JavaScript zu lösen, was nur dazu diente, die Implementierung von ... Nun ... irgendetwas zu erschweren. Wenn Sie so etwas wie Typescript nicht verwenden möchten, dokumentieren Sie, was Sie erwarten. Wenn Leute Ihre Dokumentation ignorieren, betreten sie Neuland.

Versuchen Sie nicht, einen runden Stift in ein quadratisches Loch zu zwingen, das jeder in ein rundes Loch formen kann. Das ist JavaScript. Umarme es. Kämpfe nicht dagegen an, Baby. Dokumentieren Sie es und schreiben Sie einfach wieder Code.

Greg Burghardt
quelle
0

Ich würde sagen, dass das erste Beispiel besser lesbar ist. Dies bedeutet nicht, dass für den falsch eingegebenen Satz ein Fehler ausgegeben wird. Es heißt, dass diese Funktion a benötigt DataValueSet. Die explizite Darstellung in Ihrem Code erhöht die Klarheit.

GenericSet.requireSetOfTypeverschleiert die Absicht der Typprüfung in der Druckfunktion. Es sieht so aus, als würde nach Artikeln mit Typ gesucht DataValue.

Hasen
quelle
Die Lesbarkeit scheint mir hier kein starkes Argument zu sein. Sie könnten die Dokumentation ganz klar in jedem Fall machen , indem Sie DataValuesSetgegen GenericSet<DataValue>. Vielleicht wäre es in der Tat klarer, anstatt GenericSet.requireSetOfTypedie Funktion GenericSet.assertSetOfTypeoder ähnliches zu benennen .
Daniel AR Werner
0

Angesichts der von Ihnen vorgestellten Optionen würde ich die erste Lösung vorziehen, da sie besser lesbar ist als die zweite. Wenn Sie jedoch wirklich eine Lösung im JS-Stil erstellen möchten, erstellen Sie eine Builder-Funktion, unabhängig davon, ob die Objekte vom selben Typ sind oder vom gemischten Typ ( MakeStrictCollectionvs MakeMixedCollection) sein sollten. In der Builder - Funktion, können Sie testen, ob die Art der jedes Mitglied Ihrer gegebenen Sammlung vom gleichen Typ ist oder nicht , und werfen einen Fehler oder ein Objekt von jedem Konstruktor zurückgeben, was einen zusätzlichen Typ Attribut "type":"strict"vs "type":"mixed".


Außerdem:

Sie sollten sich Typescript ansehen , das möglicherweise das ist, wonach Sie suchen. Und es gibt ein Paket, das Ihren Anforderungen mit generischen Sammlungen zu entsprechen scheint .

Thomas Junk
quelle
-1 Für MakeStrictCollection vs MakeMixedCollection. In Bezug auf die obigen Codebeispiele printDataValueswürde sich die Funktion ändern, um zu überprüfen, ob das angegebene Objekt instanceof StrictCollectionund sein Typ waren DataValues. GenericSet.requireSetOfTypekönnte genau das sein - daher scheint Ihr Vorschlag lediglich ein Implementierungsdetail für den GenericSetAnsatz zu sein.
Daniel AR Werner