Le classi di riferimento reciproco sono una conseguenza del cattivo design? [chiuso]

7

Attualmente sto lavorando a una piccola partita che ho fatto in una decina di giorni. Dal momento che sto programmando per me stesso, sono pigro e sto andando alla soluzione più semplice con (troppo) poca preoccupazione per la cattiva qualità del codice.

Tuttavia sto raggiungendo un punto in cui inizia a importare. Sto iniziando a spostare i booleani che fanno riferimento agli stati in classi ecc. E ora volevo conoscere l'opinione dei programmatori esperti sugli oggetti di riferimento reciproci.

Ciò che intendo per oggetti di riferimento reciproci è questo: abbiamo un server che può creare più giochi, come i giochi di scacchi quando due client si connettono per giocare. Ogni volta che un giocatore fa una mossa, il suo gestore di connessione deve aggiornare una scheda specifica sul server. Dopo l'aggiornamento, una volta aggiornata la scheda, è necessario trasmettere una trasmissione del nuovo stato a ciascun client.

Ho trovato comodo avere due oggetti Client nel Board (quindi Board può Client.send () per entrambi) e una Board in ogni Client (così il Client può chiamare Board.update (move)). Per qualche motivo, sono incline a pensare che questo sia generalmente cattivo e potrebbe essere evitato, ma quale è la tua opinione?

È finita così com'è, o mi sto perdendo qualcosa qui?

    
posta Arthur Havlicek 27.09.2015 - 23:23
fonte

3 risposte

8

Avere le classi che dipendono direttamente l'una dall'altra è noto come accoppiamento. Generalmente è considerato un articolo di fede, senza alcuna spiegazione fornita perché apparentemente nessuno dovrebbe nemmeno essere necessario, quell'accoppiamento è una brutta cosa perché rende il tuo sistema "inflessibile".

Il problema è che l'unica cosa peggiore della flessibilità troppo bassa è troppa flessibilità. Quando rendi tutto il più flessibile possibile, ti ritroverai con pasticci orribili come Soft Coding . E questa inflessibilità può effettivamente essere un enorme vantaggio, girando lo svantaggio percepito sulla sua testa. Lo svantaggio spesso citato è che se cambi una cosa, si romperà tutto ciò a cui è accoppiata e dovrai cambiare anche questa. Considerate questo: le modifiche a un sottosistema frequentemente (non sempre, ma più spesso di quanto si vorrebbe!) Finiscono comunque per influenzare i sottosistemi correlati. Se sono strongmente accoppiati e la tua lingua ha un sistema di tipo statico strong, allora quando esegui una modifica, il compilatore farà tutto il lavoro duro per te e ti mostrerà esattamente cosa deve essere riparato e dove Più disaccoppia le cose, più difficile è rintracciare problemi come questo.

Il che non vuol dire che tutto dovrebbe essere strongmente accoppiato, ovviamente, specialmente se vuoi che il tuo codice sia in grado di lavorare con diversi tipi di sistemi correlati. La gente chiama troppo accoppiare un incubo di manutenzione per una buona ragione. Ma fai attenzione a disaccoppiare semplicemente tutto per il disaccoppiamento di tutto, perché può essere anche peggio.

In questo caso particolare, sembra che tu non stia cercando di far funzionare il tuo codice con diversi tipi di sistemi. Il tuo Cliente non sta cercando di essere in grado di eseguire "una scacchiera, una scacchiera, un Consiglio di backgammon o una commissione Scrabble"; sta semplicemente giocando a scacchi. Quindi avere una conoscenza della classe Board non è un problema. Allo stesso modo, la Board non sta cercando di comunicare con più client diversi, quindi non ha bisogno di essere flessibile nel tipo di client con cui cerca di comunicare, e quindi, non è necessaria la complessità aggiuntiva che deriva dal fare è flessibile. Questo è un principio di programmazione pragmatico molto importante noto come YAGNI (Non ne avrai bisogno!) Tienilo a mente, e dovresti fare bene.

    
risposta data 28.09.2015 - 17:14
fonte
6

Sì, questo può essere un problema.

Quando A dipende da B, ciò significa che le modifiche in B richiedono spesso anche modifiche in A. Quando A e B dipendono l'uno dall'altro, ciò significa che i cambiamenti in uno dei due richiedono spesso modifiche nell'altro. Per motivi di manutenzione, una volta che due classi si fanno riferimento reciprocamente, potrebbero anche essere un'unica grande classe.

Come molti altri problemi di architettura del software, è improbabile che un solo riferimento reciproco come l'esempio che descrivi sia di per sé un grosso problema, ma se non rimuovi questo riferimento reciproco quando diventa fastidioso, renderà inutili molti cambiamenti futuri poco pratici. E se ti permetti di aggiungere altri riferimenti reciproci, rischi di trasformare tutte le tue piccole classi in una classe di fatto che non puoi più districare.

Come esempio molto, molto semplicistico di ciò di cui sto parlando, immagina di voler aggiungere una modalità spettatore o una classifica online o qualche altra funzionalità che richiede l'invio dello stato della scheda a "clienti" che non sono l'altro giocatore. Il cliente deve cambiare a prescindere da quando ha bisogno di sapere come chiamare SpectatorBoard.update () e Leaderboard.addScore () così come Board.update (), ma a causa del riferimento reciproco, Board deve anche cambiare in modo che può chiamare Spectator.send () e Leaderboard.sendScore (). Ora la tua complessa logica di rete è suddivisa in due classi, una delle quali chiaramente non ha alcun business a saperlo in questi dettagli.

Senza conoscere meglio le tue esigenze, il codice corrente e il linguaggio di programmazione è impossibile dire quale sia l'alternativa corretta, ma intendo dire che la necessità di inviare aggiornamenti "ha origine" nella scheda in qualche modo (forse è quella gestire l'input dell'utente), nel qual caso un'ovvia alternativa è insegnare al Consiglio di amministrazione di un evento (supponendo che la tua lingua supporti eventi, ovvero il pattern Observer), e quindi semplicemente che il Cliente si iscriva a quell'evento. Quindi il Cliente può rimanere l'unica classe che ha bisogno di conoscere la tua logica di rete.

    
risposta data 28.09.2015 - 02:10
fonte
0

L'approccio del povero uomo qui è quello di creare un modello di progettazione Mediatore, in cui le due classi citate comunicano solo al mediatore e il mediatore conosce le due classi. Puoi prendere quello che vuoi con le interfacce invece che con le classi concrete, le fabbriche per costruire i componenti, così via, ma un mediatore renderà sicuramente qualsiasi refattore più semplice lungo la strada!

    
risposta data 28.09.2015 - 17:26
fonte

Leggi altre domande sui tag