2011-01-12 26 views
8

Hier ist eine Implementierungsdetails-Frage für JavaScript-Gurus.Implementieren einer komplizierten Entscheidungstabelle in JavaScript

Ich habe eine Benutzeroberfläche mit einer Anzahl von Feldern, in denen die Werte der Felder in einer komplizierten Weise auf die Werte von sieben Bits der Eingänge abhängen. Was genau sollte für einen der möglichen 128 Werte angezeigt werden, der sich regelmäßig ändert, wenn Benutzer mehr von der Anwendung sehen?

Gerade jetzt, ich habe für diese als Entscheidungsbaum durch eine Wenn-dann-sonst-Kamm implementiert, aber es ist spröde unter den Anforderungen Änderungen und Art von schwer zu bekommen richtig.

Eine Implementierung Ansatz, den ich darüber nachgedacht habe, ist ein Array von Werten von 0x0 bis 0x7F und speichern Sie dann einen Verschluss an jedem Ort zu machen -

var tbl; // initialize it with the values 
    ... 
tbl[0x42] = function(){ doAThing(); doAnotherThing(); } 

und dann rufen Sie mit

tbl[bitsIn](); 

Dies macht zumindest die Entscheidungslogik in eine Reihe von Aufgaben.

Frage: Gibt es einen besseren Weg?

(Update: holy crap, wie würde diese Zeile über 'Ajax iphone Tags' erhalten dort Kein Wunder, war es ein wenig rätselhaft.)

aktualisieren

Also, was passiert ist ? Im Grunde nahm ich eine vierte Option, obwohl ich der ähnlich war, die ich überprüft habe. Die Logik war ausreichend komplex, dass ich schließlich ein Python-Programm erstellte, um eine Wahrheitstabelle auf dem Server zu erzeugen (Groovy Code zu erzeugen, tatsächlich ist der Host eine Grails-Anwendung) und die Entscheidungslogik vollständig in den Server zu verschieben. Jetzt interpretiert die JavaScript-Seite einfach ein JSON-Objekt, das die Werte für die verschiedenen Felder enthält.

Schließlich wird dies wahrscheinlich eine weitere Iteration durchlaufen und zu Daten in einer Datenbanktabelle werden, indiziert durch den Bitvektor.

Der tischgetriebene Teil erwies sich als der richtige Weg; Es gab bereits ein halbes Dutzend neue Änderungen in den spezifischen Anforderungen für die Anzeige.

+2

Von dem, was ich von Ihrem Problem zu verstehen, sind Ihre Refactoring Gedanken klingen, aber TBH i Ich bin mir nicht sicher aus Ihrer Beschreibung, was Sie brauchen: P –

+0

Bestimmt jedes Bit eine bestimmte Aktion? Wenn ja, warum nicht ein bitweises UND auf Ihrem Wert gegen [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40] – draeton

+0

@Martin, der Punkt ist, ob es eine andere, flexiblere Art und Weise, dies als meine Tabelle zu tun von Lambda. –

Antwort

1

Haben Sie darüber nachgedacht, Ihren Entscheidungsbaum auf dem Server zu generieren, anstatt ihn manuell zu schreiben? Verwenden Sie, was auch immer sauber ist, einfach zu arbeiten und zu modifizieren und dann kompilieren Sie diese auf hässliche und dennoch effiziente Javascript für die Client-Seite.

Ein Entscheidungsbaum ist relativ einfach als Daten darzustellen, und es ist einfach zu verstehen und mit einer traditionellen Baumdatenstruktur zu arbeiten. Sie können diesen Baum in der für Sie sinnvollen Form speichern. Validieren und ändern Sie es als Daten sollten auch einfach sein.

Dann, wenn Sie den Entscheidungsbaum verwenden müssen, kompilieren/serialisieren Sie es als großes if-the-else, switch oder Hash-Chaos in JavaScript. Dies sollte auch ziemlich geradlinig und wahrscheinlich viel einfacher sein, als zu versuchen, eine switch mit ein paar hundert Elementen zu erhalten.

2

Da die Situation (wie Sie beschrieben haben) so unregelmäßig ist, scheint es keinen besseren Weg zu geben. Trotzdem kann ich eine Verbesserung Ihres Sprungtisches vorschlagen. Sie haben erwähnt, dass Sie Fehler und Duplikate haben. Anstatt sie explizit einem Abschluss zuzuordnen, können Sie sie also benannten Funktionen zuweisen, sodass Sie den expliziten Abschluss nicht duplizieren müssen.

var doAThingAndAnother = function(){ doAThing(); doAnotherThing(); } 

var tbl; // initialize it with the values 
    ... 
tbl[0x42] = doAThingAndAnother; 
tbl[0x43] = doAThingAndAnother; 

Nicht so viel von einer Verbesserung, aber es ist das einzige, was ich denken konnte! Sie scheinen die meisten anderen Themen abgedeckt zu haben. Da es so aussieht, als ob sich die Anforderungen so sehr ändern, denke ich, dass Sie auf Eleganz verzichten müssen und ein Design haben müssen, das nicht so elegant ist, aber immer noch leicht zu ändern ist.

5

Ich sehe zwei Optionen ...

Gemeinsam ist beiden Lösungen sind die folgenden genannten Funktionen:

function aThing() {} 
function anotherThing() {} 
function aThirdThing() {} 

Der Schaltweg

function exec(bits) { 
switch(bits) { 
    case 0x00: aThing(); anotherThing(); break; 
    case 0x01: aThing(); anotherThing(); aThirdThing(); break; 
    case 0x02: aThing(); aThirdThing(); break; 
    case 0x03: anotherThing(); aThirdThing(); break; 
    ... 
    case 0x42: aThirdThing(); break; 
    ... 
    case 0x7f: ... break; 
    default: throw 'There is only 128 options :P'; 
    } 
} 

Die Karte Weg

function exec(bits) { 
    var actions = map[bits]; 
    for(var i=0, action; action=actions[i]; i++) 
     action(); 
} 

var map = { 
0x00: [aThing, anotherThing], 
0x01: [aThing, anotherThing, aThirdThing], 
0x02: [aThing, aThirdThing], 
0x03: [anotherThing, aThirdThing], 
    ... 
0x42: [aThirdThing], 
    ... 
}; 

in beiden Fällen Sie

nennen würde
+0

konnte diese Schleife nicht sein 'für (var action in action) action();'? –

+0

Es könnte aber wenig sinnvoll sein. In diesem Fall handelt es sich um ein Array von Funktionsreferenzen, und Sie möchten Arrays mit for (var i in array) nicht sowohl überlappen, weil es viel langsamer ist, als auch, weil es Ihnen in allen Browsern ungleiche Ergebnisse liefert. Einige Browser behandeln die "length" -Eigenschaft des Arrays als nur ein weiteres Mitglied des Objekts und geben Ihnen dies ebenso wie die Funktionsreferenzen. –

+0

[] .propertyIsEnumerable ('length') === false – draeton

Verwandte Themen