Come usare i campi da un oggetto dopo che un'eccezione è stata lanciata e l'oggetto non può essere completamente creato

1

Il problema che ho è che ho bisogno di informazioni da un oggetto che un metodo restituisce quando lancia un'eccezione. È un po 'difficile da descrivere, quindi ho questo esempio di codice pseudo java. Ho una soluzione, ma non mi piace (problemi elencati di seguito), e mi chiedevo se ce n'era una migliore:

public class OuterClass {

  InnerClass innerClass = new InnerClass();

  public void doOuterClass() {
    try {
      // class Container is a POJO with Strings s1, s2, and s3
      Container container = innerClass.createContainer();

      // more processing on the container that takes arg container
    } catch (Exception e) {
      // *Issue is here*: If s2 was calculated, it implies that an RPC was made,
      // which changed the state of a certain server. I need make a call using s1
      // to revert the state of that server. FYI, it is not easy to recalculate s1.
    }
  }
}

public class InnerClass {

  InnerInnerClass innerInnerClass = new InnerInnerClass();

  public Container createContainer() throws Exception {
    Container container = innerInnerClass.createContainer();

    // complex calls to various services that might throw Exception
    ...

    return container;
  }
}

public class InnerInnerClass {

  public Container createContainer() throws Exception {
    // complex calls to various services that might throw Exception
    String s1 = ...;

    // complex calls to various services that might throw Exception
    String s2 = ...;

    // complex calls to various services that might throw Exception
    String s3 = ...;

    return new Container(s1, s2, s3);
  }
}

Quello che ho cercato di fare è aggiungere Exception come campo in Container e renderlo mutabile. Come s1, s2 e s3 vengono calcolati, imposta i valori nel Container. Ci sono alcuni problemi con questo però (elenco non esaustivo):

  1. Devo circondare ogni metodo di creazione con un grosso tentativo di cattura e impostare l'eccezione sul contenitore quando viene lanciata un'eccezione. Ciò rende complicato per gli altri l'aggiunta di un nuovo codice.
  2. Container è ora modificabile.
  3. I campi Contenitore sono contrassegnati come @Nullable, il che significa che tutto il codice dopo innerClass.createContainer () dovrebbe verificare tecnicamente il null poiché l'oggetto potrebbe tecnicamente essere parzialmente costruito. (tuttavia, se non ci sono eccezioni, possiamo presumere che tutti gli elementi non siano nulli, ma questa è di nuovo un'ipotesi che deve essere ricordata.
  4. In realtà ci sono più eccezioni generate dall'eccezione, quindi per gestirle devo riscrivere l'eccezione dopo innerClass.createContainer (), o usare instanceof sull'eccezione, che è brutta.

In sintesi, la soluzione che ho provato non è mantenibile e difficile da seguire. Cosa pensi? C'è una soluzione migliore?

    
posta nmore 30.04.2016 - 04:32
fonte

1 risposta

1

Sì, c'è una soluzione migliore.
La radice del tuo problema sembra essere il tentativo di gestire l'eccezione nel posto sbagliato, dove non hai più le informazioni richieste per ripristinare alcune azioni che sono state intraprese.

Se la creazione dell'oggetto Container consiste di più passaggi che possono fallire e che hanno effetti esternamente visibili o persistenti che devono essere sottoposti a rollback se non tutti i passaggi riescono, allora dovresti gestirlo nella logica che sta creando il Container oggetto.

Ad esempio:

public class InnerInnerClass {

  public Container createContainer() throws Exception {
    // complex calls to various services that might throw Exception
    String s1 = ...;

    try {
        // complex calls to various services that might throw Exception
        String s2 = ...;

        try {
            // complex calls to various services that might throw Exception
            String s3 = ...;

            return new Container(s1, s2, s3);
        } catch (Exception)
        {
            // roll-back the effects from s2
            // re-throw the exception for further handling
        }
    } catch (Exception)
    {
        // roll-back the effects from s1
        // re-throw the exception for further handling
    }
  }
}

In questo modo, OuterClass può gestire l'incapacità di creare il contenitore senza dover affrontare la possibilità che alcuni passaggi nella creazione del contenitore possano avere avuto un effetto che deve essere ripristinato, poiché ciò era già stato risolto di.

    
risposta data 30.04.2016 - 11:11
fonte

Leggi altre domande sui tag