Come posso eseguire il rollback dell'esecuzione di un costruttore durante la creazione di una struttura dati complessa?

3

Sto costruendo un complesso albero di oggetti. Esistono cinque tipi, A , B , C , D e E . Esiste una singola istanza di A , che è il nodo radice. A ha uno o più B s come figli, ogni B ha uno o più C s come figli e così via. Il formato dati originale è uno stream che consiste di 5 numeri (ID numerici per A , B , C , D e E ) più i metadati che possono essere associati a ciascuno di essi.

Sto tentando di aggiungere un certo livello di filtraggio al mio albero. Il mio attuale approccio è quello di prendere l'input e passarlo nel costruttore per A e quindi scorrerlo verso il basso in B s che A costrutto e C s che B costruisce e così via. Tuttavia, il filtro si verifica in definitiva al livello di E . Se tutto il E s per un dato D non esiste, non voglio creare quel D . Se C non ha D s, non voglio che C esista.

Il mio pensiero iniziale è di lanciare un'eccezione, ma sembra utilizzare le eccezioni per il controllo del flusso. Sebbene alcune lingue favoriscano le eccezioni, attualmente sto lavorando in Java, dove la tendenza è che le eccezioni siano per condizioni eccezionali. Non penso che non corrispondere a un filtro sia un caso eccezionale.

Quali sono le mie opzioni per garantire che il mio albero finale contenga solo nodi con figli e il filtro sia applicato?

    
posta Thomas Owens 06.10.2015 - 21:20
fonte

2 risposte

2

Lo farei usando un Map<Id, Container> a ogni livello della struttura dati. Scrivi un metodo di supporto privato che restituirà il contenitore se già esiste o crea un nuovo Container se non esiste ancora. Questo è il metodo comunemente chiamato getOrAdd .

Come al solito, accertarsi che il contenitore sottostante esista ancora è un mucchio di codice boilerplate che si rischia di copiare ripetutamente se si sbaglia. Invece, dovresti creare la tua struttura dati per farlo, oppure puoi usare Guava per dare una mano che fornisce una serie di strumenti utili tra cui Multimap (che puoi utilizzare se i dati le strutture sono piuttosto stupide) e ForwardingMap ( che renderà più facile scrivere le proprie implementazioni di mappe se disponi di metadati a tutti i livelli). Quindi, scrivi solo get per utilizzare un Supplier / Factory (se non si utilizza Guava) se il contenitore non esiste ancora o restituisce quello esistente se lo fa.

    
risposta data 06.10.2015 - 21:36
fonte
3

Inizierò sottolineando che la creazione di oggetti complessi in un costruttore non è sempre una buona idea.

Detto questo, se è il modo in cui il tuo codice si comporta attualmente, e non vuoi cambiarlo, probabilmente dovresti essere in grado di scambiare i tuoi costruttori con le fabbriche leggere.

Invece di A () che faceva il nuovo C () e poi decidendo che non ne aveva davvero bisogno, si poteva fare (con una fabbrica o un metodo statico, a seconda della lingua): A () chiamando C # get ( ) che restituisce un C o null se è filtrato.

    
risposta data 06.10.2015 - 21:30
fonte

Leggi altre domande sui tag