Archiviazione oggetto in cui il tipo di oggetto è variabile

1

Di tanto in tanto, ci imbattiamo in un problema in cui dobbiamo archiviare un oggetto, ma non sappiamo in anticipo quale tipo di oggetto archiviamo. Ho intenzione di dare un esempio molto semplice.

Requisito: tutte le domande hanno risposte. Tutte le risposte hanno almeno una parte. Alcune risposte hanno più di una parte.

Ci concentreremo su come archiviare e recuperare risposte multiparte. Vogliamo che il nostro punto di vista o il nostro controller si comportino in modo diverso a seconda che la risposta abbia una parte o più parti.

Concettualmente (senza archiviazione oggetti) potremmo scrivere quanto segue:

Modello dati:

class Answer
    Wording (string or Array of strings)

Controller:

if ourAnswer.wording instanceof String:
    doSomethingWith(ourAnswer)
else
    foreach (answerPart in ourAnswer.wording)
        doSomethingElseWith(answerPart)

Quindi penso che sarebbe il modo più semplice possibile per soddisfare tale funzionalità, ma non sono a conoscenza di alcun database che ci consenta di archiviare i nostri oggetti in questo modo, tranne forse JSON. (Nessun POJO presumibilmente a causa del controllo di tipo statico.)

In realtà sto usando Node.js e Javascript con un database NoSQL qui e questo è il motivo per cui riesco a scappare nel mio pseudocodice senza curarmi del tempo di compilazione se il mio Answer.wording è una stringa o una matrice. Ma questo è un problema molto comune quando uso anche Java e non ho ancora trovato la soluzione più elegante. Ad esempio, immagina di provare a scriverlo in Java. Probabilmente faremmo:

public interface Answer {
    public String getAnswer();
}
public class SingleAnswer implements Answer {
    private String wording;
    public String getAnswer() {
         return this.wording;
    }
}
public class MultipartAnswer implements Answer {
    private String[] wording;
    public String getAnswer() {
         return doSomethingWithThisArray(this.wording);
    }
}

... e naturalmente questo solleva tutti i tipi di problemi strani con la separazione delle preoccupazioni - come facciamo a sapere che la nostra Risposta a più parti farà la cosa giusta con il suo array, per esempio? E se avessimo bisogno di lavorare direttamente con l'array? E così via.

Bene, questi sono tutti problemi implementativi che possiamo risolvere. Sono davvero interessato alla best practice per un linguaggio come Javascript in cui non possiamo usare una gerarchia di oggetti e in particolare, la loro memorizzazione in qualcosa come un database NoSQL o, peggio ancora, un vero database SQL. Questo problema è il tipo di cosa che si apre continuamente con lo stack LAMP.

Potrebbe esserci una soluzione semplice per questo esempio specifico: potremmo assumere che TUTTE le risposte siano risposte in più parti, alcune delle quali hanno una lunghezza della serie answerPart di 1. Bello, semplice, chiaro, facile e questo è in effetti ciò che io finito per fare. Ma cosa succede se non è così semplice e non sappiamo davvero che tipo di cosa vogliamo archiviare, ma solo che si tratta di un insieme finito di cose ben definite? Cosa succede se i nostri oggetti sono preferiti Oggetti colorati di scarpe di un millepiedi (16) o ruote di una macchina (4, funzionalità diverse da quelle che fanno le scarpe del millepiedi)?

Troppo artificiale dici? Ecco un altro esempio del mondo reale che ho trattato alcuni anni fa.

Requisito: chiedere all'utente se soffre di disturbi cardiaci. Se lo fanno, devono fornire i dettagli di quella condizione.

Dato che stavo usando lo stack LAMP, il modo più semplice per memorizzare era in una colonna del database chiamata heart_condition_details, che può essere nullo. Nei controlli in cui has_heart_condition? () Importava potevamo semplicemente restituire se heart_condition_details era nullo o no. Sfortunatamente, il framework che stavo usando (cakephp) non mi permetteva di estendere il modello di dati come quello, con un tipo booleano has_heart_condition basato sul fatto che heart_condition_details fosse vuoto.

Alla fine, ho usato colonne separate per varchar heart_condition_details e booleano has_heart_condition. Ad oggi, penso, lo rimpiango ancora.

    
posta DMCoding 25.03.2015 - 20:11
fonte

1 risposta

1

But what if it isn't so simple and we really don't know what kind of thing we want to store, only that it is one of a finite set of well-defined things?

Questo è esattamente ciò che è un unione taggata . Puoi emularli in Java utilizzando una classe base astratta con un costruttore privato e sottoclassi interne finali. Le sottoclassi interne possono utilizzare il costruttore privato, ma le classi non interne non possono, quindi si finisce con un numero finito di sottoclassi (che non possono essere ulteriormente estese perché sono final ).

public abstract class Answer {
    private Answer() { /* Prevent outside inheritance */ }

    public static final class SingleAnswer extends Answer {
        public final String answer;
        public SingleAnswer(String answer) { this.answer = answer; }
    }

    public static final class MultiPartAnswer extends Answer {
        public final String[] parts;
        public MultiPartAnswer(String[] parts) { this.parts = parts; }
    }
}

(E naturalmente puoi aggiungere getter e formattare correttamente le parentesi.)

Puoi quindi diramarti sul tipo di risposta in un modo sicuro / infallibile usando il modello Visitatori , o se hai accesso a Java 8 potresti accettare due lambdas invece di un visitatore, il che sarebbe molto meno pesante rispetto alla creazione di oggetti anonimi.

    
risposta data 25.03.2015 - 20:40
fonte

Leggi altre domande sui tag