Relazioni opzionali entità: classi separate o classe singola?

2

Consente di concentrarsi su un oggetto di dominio correlato a più altre entità (diverse!). A volte abbiamo bisogno di una relazione e talvolta di un'altra. Siamo agili e diciamo: non sappiamo in anticipo quante altre relazioni ci saranno.

In altre parole: abbiamo oggetto A correlato uno a uno a B e uno-a-molti a C e ancora one-to-one a D e così via. Ora, quando si sviluppa il livello di presentazione, spesso è necessario visualizzare molti dati; come tabella di A con B o in un altro posto A con molti C e così via.

Come modelleremo queste relazioni?

Ecco un esempio: Competition . A volte viene e deve essere utilizzato con ad es. %codice%. A volte con es. %codice%. Dato che ti interessano le prestazioni, diciamo anche che gli oggetti correlati ( Venue e lista di List<Event> s) provengono dal metodo / metodo finder / metodo finder / un join SQL (comunque lo chiami) - e che può essere iniettato in Venue usando alcuni strumenti di mappatura. In questo modo esprimiamo la relazione effettiva tra le entità.

Domanda: dovremmo mantenere entrambe le relazioni / riferimenti nella classe Event e ignorare l'altra quando ne viene usata una, oppure dovremmo creare molte classi separate, una per ogni relazione? (Non importa se è 1-1 o 1-molti, la domanda è la stessa.)

In altre parole, dovremmo avere:

[A]

Tutto nella singola classe. I metodi Getter rappresentano le relazioni. È su di noi riempire l'oggetto se la relazione è necessaria.

class Competition {
    ... competition data...

    private Venue venue;
    public Venue getVenue() {
        return venue;
    }

    private List<Event> events;
    public List<Event> getEvents() {
        return events;
    }
}

Ma poi, quando il metodo dell'applicazione restituisce un Competition non sai quali relazioni sono popolate e devi capirlo guardando il codice dei metodi dell'applicazione o il nome del metodo (es. Competition ).

[B]

Per ogni relazione abbiamo un tipo o un'interfaccia. Un modo per farlo, senza interfacce per la semplicità di questo esempio, è:

class CompetitionVenue extends Competition {
    private Venue venue;
    public Venue getVenue() {
        return venue;
    }
}

e

class CompetitionEvents extends Competition {
    private List<Event> events;
    public List<Event> getEvents() {
        return events;
    }
}

Ora il tipo parla da solo quale rapporto viene restituito e quindi il metodo dell'applicazione che lo restituisce garantisce che la relazione esiste. Ma poi ogni relazione avrebbe una sua classe o interfaccia;

EDIT:

[C]

Ogni relazione è rappresentata utilizzando una classe generica come Competition e findCompetitionWithEvents...() non ha il getter per la lista di eventi?

    
posta igor 27.03.2014 - 17:27
fonte

3 risposte

1

Cerco di seguire l'idea del "codice pulito" di non restituire mai nulla (almeno per quanto posso). Questa idea suggerisce che l'opzione B (due sottoclassi) sia l'alternativa migliore.

Ho un caso reale che spiega questo ... il nostro sistema ti permette di registrare un Ticket contro varie altre entità nel sistema, ma solo contro un tipo, quindi potresti registrarlo contro un Mill o contro a Computer . In questi casi abbiamo MillTicket e ComputerTicket . Solo ComputerTicket ha un riferimento a Computer . Sul lato SQL, sono solo chiavi esterne nullable.

Un vantaggio è che un ComputerTicket può avere tutti i tipi di campi che sono applicabili solo quando sto registrando un Ticket contro un Computer .

Ciò che impedisce è la possibilità di avere un Ticket contro 2 entità diverse, quindi questa è una decisione di progettazione con una conseguenza piuttosto significativa. Inoltre, significa che è relativamente difficile modificare retroattivamente un ComputerTicket in un MillTicket se qualcuno cambia idea. Può essere fatto ma è un dolore.

    
risposta data 27.03.2014 - 17:38
fonte
0

Il tuo modello è un chiaro esempio di astrazione, ma ti stai avvicinando dal modo sbagliato. Vuoi conoscere la posizione della competizione, ma non sai che tipo di posizione è. Quindi dovresti creare un'interfaccia o una classe astratta che definisca questa posizione (chiamiamola Location ) e quindi dedurre Venue e Event da essa.

Inoltre, stai parlando innanzitutto del modello di dominio e poi parli di join SQL. Stai mescolando insieme le due cose che è mai una buona cosa. Concentrati su uno o il secondo, ma mai su entrambi allo stesso tempo.

    
risposta data 27.03.2014 - 18:40
fonte
0

Se hai solo bisogno di usare Venue OR Event ma mai entrambi allo stesso tempo, è praticamente un tipo di somma. Ho postato una risposta qualche tempo fa mostrando come codificarle in C # . Sfortunatamente è veramente pratico con lambdas, quindi a meno che tu non stia usando Java 8, il metodo match sarà prolisso da usare. Potresti comunque utilizzare instanceof per distinguere tra le opzioni come già fai nell'opzione B. Il problema è che usando instanceof , se successivamente aggiungi un'alternativa aggiuntiva devi trovarla ogni luogo in cui hai creato if ... else if ... e aggiungi la nuova alternativa al codice. Inoltre, questo funziona solo per un numero finito di possibilità, ma suona come quello che hai qui.

Usandolo come base, potresti creare una classe Either<A, B> che contiene un valore di tipo A o tipo B, dove A e B potrebbero essere Venue e Event . Per es.

public class Competition {
    private Either<Venue, Event> venueOrEvent;
    ...
}

Se invece ciò di cui hai bisogno è un numero finito di tipi di Competition (es. ci sono esattamente 5 tipi di competizione, ognuno con il proprio set di dati) potresti semplicemente fare ciò che stavi già facendo nell'opzione B, tranne farli classi interne della classe Competition e dando a Competition un costruttore privato in modo che nessuno possa introdursi in sottoclassi aggiuntive.

    
risposta data 27.03.2014 - 18:49
fonte

Leggi altre domande sui tag