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
_______________________________________________
Interest mailing list
Interest@qt-project.org
https://lists.qt-project.org/listinfo/interest

Reply via email to