Come rimuovere riferimenti circolari in caso di interdipendenza

1

Ho fatto una ricerca approfondita su domande relative a precedenti domande, ma poiché le mie domande sono alquanto peculiari, ho deciso di crearne una nuova.

Sto implementando un'applicazione di visualizzazione (in JS). Esiste una classe, chiamata Graph , che contiene la visualizzazione di un grafico, insieme a tutti i componenti necessari (nodi, spigoli, ecc.). Ho deciso di implementare una funzionalità di clustering sul grafico, che consente all'utente di raggruppare un gruppo di nodi in un singolo cluster, a seconda di alcuni attributi. Inizialmente ho implementato questa funzionalità nella classe Graph. Tuttavia, poiché è una quantità significativa di logica, che non è direttamente correlata al grafico, penso che dovrebbe essere correttamente refactored ad un componente diverso (l'ho chiamato ClusteringEngine ). E qui arriva il problema.

ClusteringEngine ha bisogno di un riferimento a Graph, per recuperare nodi, bordi ecc. Quindi, se ClusteringEngine è implementato come sottocomponente di una classe esterna (un CentralController), il grafico delle dipendenze sarà come:

CentralController ---> Graph <----\
                 \                 \
                  \--> ClusteringEngine

che sembra molto accoppiato. Un'altra opzione è quella di implementare ClusteringEngine come componente di Graph, dove finirò con un riferimento circolare:

CentralController -----> Graph <-----> ClusteringEngine

che è di nuovo altamente accoppiato. Mi stavo chiedendo se c'è un modo per evitare questo problema e progettarlo in un modo migliore.

P.S. Ho pensato all'Observer Design Pattern, ma poiché non esiste un contesto di eventi-messaggi, penso che non sia appropriato per questo caso.

    
posta Dimos 21.06.2016 - 13:07
fonte

2 risposte

3

which seems highly coupled.

Non è molto accoppiato. Infatti, è lo stato di accoppiamento minimo . Il ClusteringEngine sempre dipenderà dal Graph , indipendentemente da ciò che fai. Inoltre, il CentralController o il Graph deve dipendere da ClusteringEngine , altrimenti non ci sarà alcun cluster nel sistema. E infine, si considera che se CentralController sta gestendo per es. l'input dell'utente e l'input dell'utente possono causare il clustering, inoltre è totalmente inevitabile che CentralController dipenda da ClusteringEngine .

Tra queste due scelte, è chiaramente meglio che CentralController dipenda da ClusteringEngine . Non è circolare ed è abbastanza ragionevole che il controllore centrale dipenda dalle cose per far accadere le cose, e fondamentalmente deve avere comunque quella dipendenza.

Non c'è niente di sbagliato nella tua prima alternativa.

    
risposta data 21.06.2016 - 13:36
fonte
0

Il metodo standard per risolvere i riferimenti circolari (e rimuovere l'accoppiamento) nei sistemi orientati agli oggetti è inversione di dipendenza . Per fare ciò, prenderemo una delle tue classi concrete (molto probabilmente ClusteringEngine , poiché sembra la più autosufficiente, ma teoricamente almeno potresti farlo per il tuo Graph ) e dichiarare un'interfaccia per questo. Tutto il codice esistente viene modificato per utilizzare l'interfaccia e un'istanza del concreto ClusteringEngine (o un oggetto factory che può produrli, se ne occorrono più di uno) viene quindi fornita al codice da una fonte esterna, probabilmente utilizzando una qualche forma di iniezione di dipendenza. L'idea di utilizzare questo processo per rimuovere l'accoppiamento dai componenti di alto livello a quelli di livello inferiore costituisce il principio di inversione di dipendenza , che è la D dei principi di progettazione SOLID.

Poiché stai usando un linguaggio dinamico, non c'è bisogno (o abilità) di dichiarare letteralmente un'interfaccia in quanto tale, ma sarebbe una buona idea documentare nella documentazione dell'oggetto grafico il protocollo usato per comunicare tra esso e il motore di clustering e come viene iniettato il motore di clustering (ad es. tramite un parametro costruttore).

    
risposta data 21.06.2016 - 13:28
fonte