[Interest] Using a single shared Object as a message bus throughout the application?
Tarre Tarkas
mail.tarre at simplelogin.co
Wed Jun 9 21:11:51 CEST 2021
I'm working on a daemon that needs to stay flexible/tweakable. I get
lots of random requirements in the form of "system needs to do X when Y
happens and if conditions A B and C are met".
Qt's doc and examples seems to exclusively encourage putting signals in
each component's class definitions. So that's what I did previously.
However I recently found out that you can actually emit a signal in a
different QObject. I always thought the "emit MySignal()" to be like a
private call, but no, signals are public functions, you can do
"someobj->MySignal()", or better yet "Q_EMIT someobj->MySignal()" to
make it stand out more.
I'd like to hear your thoughts on an application architecture style
where you use a single shared object as a public message bus throughout
the entire app. So all the components of the app have a reference to
this QObject, all the "public" signals used by the application are
defined in this QObject instead of being defined in the object that
emits them.
I've written a very simple example app to showcase this:
https://gitlab.com/tarre/message-bus-test
Notice how the features in the 2nd and 3rd commits were bolted on to the
existing architecture in a very straight-forward way, without having to
modify unrelated source files.
Pros:
1) Simpler application architecture. Since there's just a single source
of major events, a new developer doesn't need to understand (as much)
where their code fits with all the rest. They can add certain features
by just writing signal handlers for signals coming from that single
event bus. Also, they can discover how components interact with each
other by searching for the usage of each signal from that single file.
When writing new components, they don't need to think as much where to
place it, since there's already this structure in place.
2) Signals emitted by objects created at a low "depth" (for example
Hardware -> SensorManager -> TemperatureSensor) can be used by
components anywhere in the app in a simple clean way, without writing
repetitive boilerplate code just to be able to connect a signal to a
slot
3) If there's a refactoring somewhere, if a different component is now
responsible for emitting SignalX, consumers don't have to change
anything. Previously the only way to do this would be to use interfaces,
which is boilerplatey.
Cons:
1) Not Qt-ic (whatever the Qt equivalent of "pythonic" is)
2) You lose the ability to use sender() to get a reference to the
QObject* that did the real emit. With this, the sender is always the
message bus object. (Correct me if I'm wrong. If there's a way to get
the sender without adding it as an argument in every signal, that would
be wonderful.)
What do you think?
Tarre
More information about the Interest
mailing list