Background: My company is working with camera systems. In the beginning we built our application around different models/setups of them, which i.e. consisted of different cameras or procedures to acquire and combine the data they acquired. However, we were always limited to having a single active system in our application. Some day we had the idea to link multiple camera systems together to acquire more data simultaneously in shorter periods of time. Since then, we are having trouble to cleanly represent this in our software.
Conceptually we have this very simplified design:
class ICamSystem
{}
class SomeCamSystemImpl : public ICamSystem
{}
class MultiCamSystem
{
std::vector<ICamSystem> cam_systems;
}
The big decision is whether or not we should have MultiCamSystem derive and implement ICamSystem. At first glance this seems very reasonable because in theory a MultiCamSystem should support pretty much the same set of operations any ICamSystem does. In fact, most of what MultiCamSystem's implementations do is just forwarding a method call to all of its composite camera systems. Deciding against this also means we would have to bloat every single call site with a distinction of cases between having a single camera system or a multi camera system. On the other hand, following Liskov's Substitution Principle a MultiCamSystem just isn't a ICamSystem and has led to all sorts of follow-up problems. Two very simple examples:
ICamSystem::set_parameter
has a very natural implementation for a camera system: It either succeeds and sets the parameter or fails with an exception. On a multi camera system I'd intuitively want to implement it like this:
MultiCamSystem::set_parameter( const Param& p )
{
for(auto* cs : cam_systems)
cs->set_parameter(p)
}
But this doesn't make sense in some cases because each camera system might have different ranges of valid/acceptable parameters. For example setting the exposure this way most likely doesn't make much sense because due to external lighting conditions I most often have to adjust them for each system individually which breaks my abstraction of having a single camera system accepting a single exposure time. I also need to worry about error handling, i.e. when an operation just fails on a subset of the camera systems.
Data ICamSystem::acquire_data() or
SystemID ICamSystem::getID()
Before, I just had a single return value from a method. With a multi camera system this rather has to be:
std::vector<Data> ICamSystem::acquire_data() or
std::vector<SystemID> ICamSystem::getID()
so again this breaks my abstraction. I could of course change the signature in the abstract interface and have single camera systems return a vector of size 1, too. But it seems ill-advised to taylor a generic and perfectly reasonable interface to specific implementations of it.
What is a better way to represent this then?