I am writing a complex GUI in Java with many components on several screens working on top of and interacting with a shared piece of logic and model. Clearly there are some circular dependencies between the "gui" and "controller/logic": User actions in GUI are forwarded to controller, which performs some task and then needs to reflect those changes in all GUIs. Something may happen in background that makes controller push updates to GUIs. And so on.
Now, here's my question. Listener or observer pattern works great for pushing updates to GUI. Is it OK to make my GUI depend on a concrete controller class directly? Why/why not? There is (and is always going to be) only one such controller. There is like a dozen controller calls that the GUIs need for polling state and executing actions - I am not in love with the idea of a handful of trivial callback interfaces that are always going to only have one implementation, nor one giant callback interface for all kinds actions.
Is it OK to make my GUI depend on a concrete controller class directly? Why/why not?
No: Because loose coupling is fundamental to good design. Depend on abstractions. Depending on implementations makes it impossible to substitute one implementation for another without recompiling the dependent at the very least. Tightly coupling any two classes impedes future flexibility.
Yes: It's a judgement call. If loose coupling definitely has no future benefit and is too expensive to justify, couple away.
But really try not to. Having the GUI depend on the controller is a valid design decision. But always depend on abstractions, never implementations. Come on... you knew that. I mean, okay, if nobody ever wants to switch out the controller, then you haven't gained anything by using an interface. Except peace of mind, knowing you wrote tidier, less-coupled code. And arguably easier to test.
As for the choice of how the communication between GUI and controller occur, it's a toss-up. You could use events, but wiring them up is a drag and they won't cross app boundaries. But by using events you may feel you have the loosest possible coupling. GUI and controller never need to address (abstractions of) each other except to initially wire up the events. That might feel nice. Or you could use method calls against interfaces, which may feel like a slightly tighter coupling, but it's hardly different really. Any way you do it, X has to know things about Y for them to communicate.
Circular dependencies between GUI and controller are okay (on abstractions!). There are many variations of the MVC pattern. Every time I use it, I mold it to my needs/mood. That said, I do try to avoid circular dependencies. I prefer to limit dependencies to one direction. Or none at all!
For example in my current project the controllers know about the views, but the views have absolutely no idea that the controllers exit. The controllers susbcribe to the views' events, and pass data back to them via a single state object which the view binds to. The state class is the only thing the view depends on. And the only thing the controller knows about the view is it's interface and the type of its state object. And those things are defined in an external module so that the view module can be removed completely and the controller will still compile, and vice-versa. This is a very loose coupling. Almost none at all (both sides depend on a third module instead).
Some people do it the other way 'round.
Reasons to avoid concrete dependencies
I completely agree with @Charles when he says that:
loose coupling is fundamental to good design.
the reasons are clear and he already explained them. I'd like just to share with you a pattern slightly different from the MVC, where the view and the controller are the same entity. It's called Model-Delegate and it's used by Swing. The linked article describe it deeply.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With