I made an extensive research in previousv related questions, but since my questions is somewhat peculiar, I decided to create this new one.
I am implementing a visualisation application (in JS). There is a class, called Graph, that contains the visualisation of a graph, along with all the necessary components (nodes, edges etc.). I decided to implement a clustering functionality over the Graph, that enables the user to cluster a group of nodes to a single cluster, depending on some attributes. I initially implemented this functionality in the Graph class. However, since it is a significant amount of logic, that is not directly related to the Graph, I think it should be properly refactored to a different component (I called it ClusteringEngine). And here comes the issue.
ClusteringEngine needs a reference to Graph, in order to retrieve nodes, edges etc. So, if ClusteringEngine is implemented as a sub-component of an outer class (a CentralController), the dependency graph would be like:
CentralController ---> Graph <----\
\ \
\--> ClusteringEngine
which seems highly coupled. Another option is to implement ClusteringEngine as a component of Graph, where I will end up with a circular reference:
CentralController -----> Graph <-----> ClusteringEngine
which is again highly coupled.
I was wondering if there is a way to avoid this problem and design it in a better way.
P.S. I have thought of the Observer Design Pattern, but since there is no context of events-messages, I think it is not so appropriate for this case.
Best Answer
It's not highly coupled. In fact, it's the minimum coupling state. The
ClusteringEngine
will always depend on theGraph
, no matter what you do. Furthermore, either theCentralController
or theGraph
must depend on theClusteringEngine
, else there won't be any clustering in the system. And finally, one considers that if theCentralController
is handling e.g. user input, and the user input can cause the clustering, it's also totally unavoidable for theCentralController
to depend on theClusteringEngine
.Between these two choices, it's clearly better for the
CentralController
to depend on theClusteringEngine
. It's not circular and it's quite reasonable for the central controller to depend on things to make things happen, and it basically has to have that dependency anyway.There's nothing wrong with your first alternative.