2011-01-12 20 views
8

Oto szczegółowe pytanie dotyczące implementacji guru JavaScript.Implementacja skomplikowanej tabeli decyzji w JavaScript

Mam interfejs użytkownika z pewną liczbą pól, w których wartości pól zależą w skomplikowany sposób od wartości siedmiu bitów danych wejściowych. Co dokładnie powinno być wyświetlane dla jednej z możliwych 128 wartości, która zmienia się regularnie, gdy użytkownicy widzą więcej aplikacji?

W tej chwili używam tego jako drzewa decyzyjnego przez grzebień if-then-else, ale jest on kruchy pod zmianami wymagań i jest trudny do uzyskania.

podejście Jedna realizacja Myślałem o to, aby tablicę wartości od 0x0 do 0x7F, a następnie zapisać zamknięcie w każdym miejscu -

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

a następnie powołać je

tbl[bitsIn](); 

To przynajmniej sprawia, że ​​logika decyzyjna staje się wiązką zadań.

Pytanie: czy jest lepszy sposób?

(Aktualizacja: kurczę, skąd ta linia o „ajax tagów iphone” tam dostać Nic więc dziwnego, że to trochę zastanawiające.)

Aktualizacja

Więc co się stało ? Zasadniczo wziąłem czwartą opcję, chociaż podobną do tej, którą sprawdziłem. Logika była wystarczająco złożona, że ​​w końcu zbudowałem program w języku Python, aby wygenerować tabelę prawdy na serwerze (generując kod Groovy, w rzeczywistości hostem jest aplikacja Grails) i całkowicie przenieść logikę decyzji do serwera. Teraz strona JavaScript po prostu interpretuje obiekt JSON zawierający wartości dla różnych pól.

Ostatecznie prawdopodobnie przejdzie jeszcze jedną iterację i stanie się danymi w tabeli bazy danych, indeksowanej przez wektor bitów.

Część napędzana blatem stołowym z pewnością okazała się być najlepszym rozwiązaniem; nastąpiło już pół tuzina nowych zmian w szczególnych wymaganiach dotyczących wyświetlania.

+2

z tego co rozumiem Twojego problemu, twoje myśli refactoring są zdrowe, ale ja tbh nie jestem pewien z Twojego opisu, czego potrzebujesz: P –

+0

Czy każdy bit determinuje określone działanie? Jeśli tak, dlaczego nie wykonać bitowej ORAZ wartości na [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40] – draeton

+0

@Martin, chodzi o to, czy istnieje inny, bardziej elastyczny sposób robienia tego niż mój stół lambdas. –

Odpowiedz

1

Czy rozważałeś wygenerowanie drzewa decyzyjnego na serwerze, zamiast pisać je ręcznie? Użyj dowolnej reprezentacji, która jest czysta, łatwa w użyciu i zmodyfikuj, a następnie skompiluj ją do brzydkiego, ale wydajnego javascript po stronie klienta.

Drzewo decyzji jest dość łatwe do przedstawienia jako dane i jest łatwe do zrozumienia i pracy z tradycyjną strukturą danych drzewa. Możesz przechowywać to drzewo w jakiejkolwiek formie, która ma dla ciebie sens. Walidowanie i modyfikowanie go jako danych również powinno być proste.

Następnie, gdy potrzebujesz użyć drzewa decyzyjnego, po prostu skompiluj je/serializuj z JavaScriptem jako dużym if-the-else, switch lub hashem. To powinno być dość proste i prawdopodobnie dużo łatwiejsze niż próba utrzymania switch z kilkoma setkami elementów.

2

Ponieważ sytuacja (jak już wspomniano) jest tak nieregularna, nie wydaje się, że jest lepszy sposób. Chociaż mogę zasugerować ulepszenie twojej tabeli skoku. Wspomniałeś, że masz błędy i duplikaty. Dlatego zamiast jawnie przypisywać je do zamknięcia, można przypisać je do nazwanych funkcji, aby nie trzeba było duplikować wyraźnego zamknięcia.

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

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

Nie za dużo poprawy, ale to jedyna rzecz, o której mogłem pomyśleć! Wygląda na to, że poradziłeś sobie z większością innych problemów. Ponieważ wygląda na to, że wymagania zmieniają się tak bardzo, myślę, że być może trzeba będzie zrezygnować z elegancji i mieć projekt, który nie jest tak elegancki, ale wciąż łatwy do zmiany.

5

Widzę dwie opcje ...

Wspólne dla obu rozwiązań są następujące nazwane funkcje:

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

Sposób przełącznik

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'; 
    } 
} 

Mapa sposób

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], 
    ... 
}; 

w obu przypadkach, że zadzwonisz

exec(0x42); 
+0

nie może tej pętli być 'dla (var akcja w akcji) action();'? –

+0

Może, ale nie miałoby sensu. Akcje w tym przypadku są tablicą odwołań do funkcji i nie chcemy pętli nad tablicami dla (var i in array) zarówno dlatego, że jest znacznie wolniejsza, jak i dlatego, że daje nierówne wyniki w różnych przeglądarkach. Niektóre przeglądarki traktują właściwość "length" w tablicy jako tylko inny element obiektu i udostępniają ją tak samo, jak odwołania do funkcji. –

+0

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

Powiązane problemy