Evita il campo mutabile nel gestore di eventi

1

Ho un gestore di eventi che crea oggetti per i quali ha bisogno di dati sia prima che dopo un evento. Il gestore di eventi stesso implementa il WebDriverEventListener interfaccia e viene registrato di conseguenza. Cioè, non ho il controllo su come la classe viene invocata.

Per creare gli oggetti, utilizzo un campo mutabile. Ecco un semplice esempio (in Java):

public class MyEventHandler {

    private MyType myMutableField;

    public void beforeEvent(DataA a) {
        myMutableField = new MyType();
        myMutableField.setA(a);
    }

    public void afterEvent(DataB b) {
        myMutableField.setB(b);
        // Do something with myMutableField...
    }

}

Per evitare invocazioni di metodi inappropriate (ad esempio invocazioni consecutive di beforeEvent o afterEvent ), faccio quanto segue:

public class MyEventHandler {

    private MyType myMutableField;

    public void beforeEvent(DataA a) {
        if ( myMutableField != null ) {
            throw new IllegalStateException();
        }
        // ...
    }

    public void afterEvent(DataB b) {
        // ...
        myMutableField = null;
    }

}

Ho anche implementato meccanismi tali che i setter possono essere richiamati una sola volta.

Tuttavia, non sono molto contento di questo approccio al design e mi chiedo se c'è un pattern che mi aiuta a) evitare il campo mutabile e / o b) rendere MyType immutabile.

    
posta beatngu13 11.12.2018 - 21:00
fonte

2 risposte

1

I have also implemented mechanisms such that setters can be invoked only once.

Perché non "cambiamo la logica? Rendiamogli eseguibile "almeno una volta" e rendilo idempotente in modo che non devi essere preoccupato per il numero di chiamate successive.

public class MyEventHandler {

    private MyType myMutableField;

    public void beforeEvent(DataA a) {

        if ( stateBeforeEvent ) {
            runMyCode(a);
        }
    }

    public void afterEvent(DataB b) {
         if (stateAfterEvent) {
             runMyCode(a,b);
         }
    }

}

Per brevità, non ho dato alcuna implementazione per stateBeforeEvent e stateAfterEvent . Come ottenere e mantenere entrambi gli stati (condizioni) dipende dalle risorse disponibili.

Nota che ho rimosso il lancio delle eccezioni. A meno che non sia necessario interrompere l'intero percorso di esecuzione, ho trovato che fosse abbastanza "difensivo". Troppo rigido. Se hai ancora bisogno di lanciare un'eccezione, dobbiamo apportare alcune modifiche

public class MyEventHandler {

    private MyType myMutableField;

    public void beforeEvent(DataA a) {

        if ( !stateBeforeEvent ) {
            throw IllegalStateException("BeforeEvent has been already executed!");
        }
       runMyCode(a);
    }

    public void afterEvent(DataB b) {
         if (!stateAfterEvent) {
           throw IllegalStateException("AfterEvent has been already executed!");
         }
         runMyCode(a,b);
    }

}

Tuttavia, non sono sicuro se possiamo etichettare questi metodi come "idempotenti". Probabilmente no.

Link correlati

risposta data 12.12.2018 - 14:57
fonte
0

Sembra che il tuo utilizzo del codice sia simile a questo:

MyEventHandler meh = new MyEventHandler();
meh.beforeEvent(a);
DataB b = someCalculation();
meh.afterEvent(b);

Quando avrebbe potuto assomigliare a questo:

MyEventHandler meh = new MyEventHandler(a);
DataB b = someCalculation();
meh.afterEvent(b);

Fatto in questo modo tutto può essere immutabile. Questo è lo stesso trucco in cui le chiusure si svolgono nei linguaggi funzionali. Questo è il modo in cui il trucco appare in un linguaggio orientato agli oggetti.

In entrambi i casi il trucco consiste fondamentalmente nel salvare qualcosa che ora sai usare con qualcosa che imparerai in seguito. Forse da qualche altra parte.

Dichiarazione di non responsabilità: sto solo utilizzando questi nomi per poterli abbinare al codice originale. Si prega di migliorarli prima di usare questo.

    
risposta data 12.12.2018 - 07:41
fonte

Leggi altre domande sui tag