I'm doing the analysis for a software which I've had in mind for a long time. Its purpose is to turn sound into an image, apply graphical transformations on it, and turn it back into sound to hear the result. I plan to write it in C++ and I want to make it as modular as possible. As I am relatively inexperienced in modular design, my approach to the problem may be naive.
The app would be an assembly of several Modules
which have DataInputs
and DataOutputs
that could be connected to each other. Basically, when a module has some data to send, it can tell one of its outputs to send a DataBlock
to all of the inputs it is connected to, and these inputs would store the data block until their own module tells them to read it for further processing. This yields the following class diagram (excerpt):
The part I'm really not sure about is which type the inner data (DataBlock::data
) should take. Up to now I've put void*
as a type because it would allow me to statically cast it back into anything I want it to be without much trouble, but for many reasons which I'm not going to enumerate here, this is obviously not a solution I want to go with.
A solution I've also come up with is to make an abstract BaseData
type which any concrete data type would inherit from, like so:
I think this would be an okay solution, but I'm concerned about using inheritance "just" to make it so concrete data types have something in common while they represent completely different stuff. With this solution, modules would have to handle data blocks differently based on their type (given by the DataBlock::dataType
field), which I think is fine if done correctly.
What is this design worth? Am I headed in the right direction or am I going to suffer the pain of a thousand fell gods because of some flaw I overlooked? What are potential alternatives and/or well-known design patterns for that purpose?
DataBlock
? Why is it necessary anyway to store different types that will only be selected at runtime (so it can't be expresses with a simple template)? I have a vague feeling of YAGNI here.DataBlocks
will store audio samples as well as pixel data, or even commands in some cases. I failed to mention that previously, sorry. IMHO, this could be useful for the audio playback module for example: it needs to receive audio samples to play as well as commands to know when to start and to stop. That's why I think I need different types of data blocks. However, they need to be all passed through the same kind of data pipelines, hence the inheritance from a common abstract type. Can you elaborate on how templates could be used in this case?DataInput<Audio>
, which in turn hasDataBlock<Audio>
which is by the type system guaranteed to only store audio, not something else. — Commands are another thing, and I daresay you should probably handle them in a separate fashion entirely.