Memento con stato opzionale?

0

Modifica Come sottolineato da Steve Evers e pdr, non sto implementando correttamente il pattern di Memento, il mio design è in realtà State pattern.

Menu Programma

Ho creato un programma di menu basato su console con più livelli che seleziona un determinato test da eseguire. Ogni livello descrive più precisamente l'operazione. A qualsiasi livello puoi digitare indietro per tornare indietro di un livello ( memento ).

Level 1: Server Type?
             [1] Server A [2] Server B 
Level 2: Server environment?
          [1] test [2] production
Level 3: Test type?
          [1] load [2] unit
Level 4: Data Collection?
          [1] Legal docs [2] Corporate docs
Level 4.5 (optional): Load Test Type
          [2] Multi TIF [2] Single PDF
Level 5: Command Type?
          [1] Move [2] Copy [3] Remove [4] Custom
Level 6: Enter a keyword
          [setup, cleanup, run]

design

States

PROBLEMA:

In questo momento l'enume degli STATI è il fattore determinante su quale stato è INDIETRO e quale stato è NEXT eppure non sa nulla su quale sia lo stato del ricordo corrente.

Qualcuno ha riscontrato un problema simile e ha trovato un modo efficace per gestire i ricordi con lo stato opzionale?

static enum STATES {
    SERVER, ENVIRONMENT, TEST_TYPE, COLLECTION, COMMAND_TYPE, KEYWORD, FINISHED
}

Soluzione possibile (non flessibile)

In riferimento al mio codice qui sotto, ogni istruzione case nella classe Menu può controllare lo stato di currentMemo e quindi impostare lo STATE (enum) di conseguenza per passare al Builder. Tuttavia, questo non sembra flessibile e molto flessibile da cambiare e non riesco a vedere un modo efficace di ridefinire il design.

class Menu extends StateConscious {
    private State state;
    private Scanner reader;
    private ServerUtils utility;

    Menu() {
        state = new State();
        reader = new Scanner(System.in);
        utility = new ServerUtils();
    }

    // Recurring menu logic
    public void startPromptingLoop() {

        List<State> states = new ArrayList<>();
        states.add(new State());

        boolean redoInput = false;
        boolean userIsDone = false;

        while (true) {
            // get Memento from last loop
            Memento currentMemento = states.get(states.size() - 1)
                    .saveMemento();
            if (currentMemento == null)
                currentMemento = new Memento.Builder(0).build();

            if (!redoInput)
                System.out.println(currentMemento.prompt);
            redoInput = false;

            // prepare Memento for next loop
            Memento nextMemento = null;
            STATES state = STATES.values()[states.size() - 1];

            // get user input
            String selection = reader.nextLine();

            switch (selection) {

            case "exit":
                reader.close();
                return; // only escape

            case "quit":
                nextMemento = new Memento.Builder(first(), currentMemento,
                        selection).build();
                states.clear();
                break;

            case "back":
                nextMemento = new Memento.Builder(previous(state),
                        currentMemento, selection).build();
                if (states.size() <= 1) {
                    states.remove(0);
                } else {
                    states.remove(states.size() - 1);
                    states.remove(states.size() - 1);
                }
                break;

            case "1":
                nextMemento = new Memento.Builder(next(state), currentMemento,
                        selection).build();
                break;

            case "2":
                nextMemento = new Memento.Builder(next(state), currentMemento,
                        selection).build();
                break;

            case "3":
                nextMemento = new Memento.Builder(next(state), currentMemento,
                        selection).build();
                break;

            case "4":
                nextMemento = new Memento.Builder(next(state), currentMemento,
                        selection).build();
                break;

            default:
                if (state.equals(STATES.CATEGORY)) {
                    String command = selection;
                    System.out.println("Executing " + command + " command on: "
                            + currentMemento.type + " "
                            + currentMemento.environment);
                    utility.executeCommand(currentMemento.nickname, command);
                    userIsDone = true;
                    states.clear();
                    nextMemento = new Memento.Builder(first(), currentMemento,
                            selection).build();
                } else if (state.equals(STATES.KEYWORD)) {
                    nextMemento = new Memento.Builder(next(state),
                            currentMemento, selection).build();
                    states.clear();
                    nextMemento = new Memento.Builder(first(), currentMemento,
                            selection).build();
                } else {

                    redoInput = true;
                    System.out.println("give it another try");
                    continue;
                }
                break;
            }

            if (userIsDone) {

                // start the recurring menu over from the beginning

                for (int i = 0; i < states.size(); i++) {
                    if (i != 0) {
                        states.remove(i); // remove all except first
                    }
                }
                reader = new Scanner(System.in);
                this.state = new State();
                userIsDone = false;
            }

            if (!redoInput) {
                this.state.restoreMemento(nextMemento);
                states.add(this.state);
            }
        }
    }
}
    
posta Korey Hinton 21.06.2013 - 18:50
fonte

2 risposte

0

Ho deciso di seguire il modello di stato * che avevo già implementato e ho trovato una soluzione piuttosto semplice che non comportava molte ristrutturazioni del codice. Ho aggiunto uno stato OPZIONALE all'enum degli STATI e ho dato allo stato cosciente un optionalFlag booleano. Per i metodi StateConscious.next () e StateConscious.previous (), darei lo stato successivo o precedente corretto in base all'impostazione del parametro opzionale.

Sono state apportate modifiche al codice aggiuntive per supportare il prompt del menu aggiuntivo, ma è stato facilmente aggiunto.

Grazie ad Amy Blankenship, pdr e Steve Evers per la loro intuizione!

* Chiarimento: dopo aver postato una domanda mi sono reso conto che sto usando il pattern di stato non il pattern di Memento

    
risposta data 24.06.2013 - 16:39
fonte
1

Ecco come ho gestito un problema simile, anche se non penso che la mia implementazione abbia seguito rigorosamente Memento. Si noti che stavo programmando in ActionScript, che ha un sistema di eventi piuttosto robusto su cui tutto ruota intorno. La mia comprensione del fatto che gli eventi in Java non si centrano effettivamente attorno a un oggetto evento, quindi potresti non essere in grado di fare ciò che ho fatto. Anche così, potrebbero esserci alcuni concetti che potresti applicare.

Fondamentalmente, tutto che è successo nel programma è stato il risultato di un evento che ha attivato un comando. Ogni comando sapeva come annullare se stesso. Questa conoscenza è stata incapsulata in sottoclassi di una classe UndoStep. L'UndoStep verrebbe archiviato in un elenco a doppio collegamento, insieme all'evento che ha attivato il comando.

Quando è stato ricevuto un evento "Annulla", il Comando per quello guarderebbe il collegamento corrente nella catena ed eseguirà il passo di annullamento, quindi tornerà indietro di un collegamento. Se è stato ricevuto un evento "Ripristina", il Comando invierà l'evento originale, che ha restituito esattamente lo stesso risultato. Non riesco a ricordare se questo potrebbe andare avanti sulla catena (il che porterebbe a più ripetizioni) o semplicemente aggiungere un nuovo collegamento alla fine, che eliminerebbe tutti gli altri Undos.

    
risposta data 21.06.2013 - 19:34
fonte

Leggi altre domande sui tag