Design di classe con relazioni bidirezionali

4

Questa è una domanda puramente di design.

Voglio portare a Java un bel gioco educativo "Bug Brain". In questo gioco si progettano reti neurali composte da tre elementi: neuroni, nodi e sinapsi. Neuron è usato per eseguire un qualche tipo di elaborazione sui suoi segnali di ingresso per produrre l'output desiderato; può essere collegato ad altri neuroni / nodi (le connessioni sono unidirezionali e ponderate). Possiamo pensare ai nodi come alle giunzioni - possono anche essere collegati ad altri neuroni / nodi (e queste connessioni sono anche unidirezionali e ponderate), ma il peso di noi non può cambiare il peso delle connessioni di input. Synapse è una connessione tra questi due elementi. Per riassumere: i neuroni e i nodi hanno sia input che output (ad altri neuroni / nodi) e fanno alcuni input > l'elaborazione degli output.

D: Ora, come progetteresti questa struttura di classe? Questo è uno schizzo che ho "prodotto" finora: screenshot del design

Poiché l'operazione "connetti due join (es. neurone / nodo)" ha tre responsabilità (aggiungi synapse, aggiungi output a join A, aggiungi input a join B) Ho deciso di metterlo come methid statico in un controller classe. Ovviamente potrei evitare queste relazioni bidirezionali tra gli elementi: non devo tenere traccia delle uscite, solo degli input ma ci sono altri limiti, ad es. ci possono essere solo 8 I / O per join, quindi dovrei ripetere tutte le sinapsi ogni volta che aggiungo una connessione per vedere se c'è ancora un posto dove aggiungerla. In questo caso (questo gioco) non avrai troppe connessioni in modo da non colpire le prestazioni, ma mi piacerebbe sapere come affrontare tali situazioni in generale.

Poiché è il fondamento di tutta questa logica di questo progetto mi piacerebbe averlo fatto correttamente. Tutti i suggerimenti sono benvenuti;)

    
posta Paweł Kłeczek 09.06.2013 - 08:11
fonte

1 risposta

1

Le associazioni bidirezionali in un design di classe sono possibili, ma arrivano sempre a un prezzo pesante, che dovresti conoscere e che devi essere disposto a pagare.

In generale, mi piace evitare le associazioni bidirezionali con l'unica eccezione delle prestazioni. Come hai detto, senza conoscere le altre direzioni, potresti dover scorrere tutti gli altri oggetti per trovare quello giusto (o contarli nel tuo caso). Questo può essere costoso, ma può anche essere risolto in modi diversi dalla creazione di una relazione bidirezionale (ad esempio le classi di associazione con le cache).

Come puoi benissimo ottenere centinaia di sinapsi, non è certamente buono passarle sopra per poter verificare se qualcosa è collegabile, quindi penso che la tua associazione bidirezionale possa essere un'opzione valida qui. Dipende da cosa intendi esattamente con questo gioco

won't have too many connections.

Se puoi permetterti il loop, allora ti suggerisco di farlo. Se mantenete la relazione bidirezionale, dovrete essere estremamente attenti a mantenere il vostro modello coerente. Ogni volta che tocchi una di queste associazioni, devi assicurarti di aggiornare atomicamente l'intero modello per renderlo nuovamente coerente.

È abbastanza difficile garantire che ogni modifica sia correttamente riflessa per tutti gli oggetti / associazioni coinvolti, ma una volta aggiunta la concorrenza diventa ancora più brutta, perché non vuoi mai che un altro thread veda il modello in un stato intermedio, dove è stata aggiunta / rimossa una sola direzione.

Anche se utilizzi strumenti come Hibernate, che supportano le relazioni bidirezionali fuori dalla scatola, ottieni altri compromessi. Ad esempio, se si combina l'ibernazione con il recupero appetitoso, si rischia di leggere l'intera rete neurale dal database, ogni volta che si chiama un join. Fa tutto parte del prezzo da pagare.

Si noti inoltre che l'omissione della relazione bidirezionale e l'aggiunta di alcune classi di helper che tengono traccia del numero di input / output, invece, non è una buona idea. Per prima cosa, dividi la responsabilità di aggiornamenti di modelli coerenti a qualcosa di diverso dal tuo modello principale, e in secondo luogo, la logica implicita per mantenere le cose coerenti deve essere aggiunta in entrambi i casi. Puoi accettare le prestazioni scadenti del ciclo o potresti ragionevolmente migliorarlo con una ricerca memorizzata nella cache che è più facile da aggiornare e non deve necessariamente essere completa.

In sintesi: le relazioni bidirezionali sono possibili, ma dovrebbero essere prese in considerazione solo quando non è possibile aggirare la loro assenza in modo fattibile.

    
risposta data 10.06.2013 - 07:26
fonte

Leggi altre domande sui tag