Introduction: I come from a mechanical engineering background, but took a class in embedded software programming (on a lovely little robot) with the intention of improving some skills I had in programming already. However, the class was largely unsatisfactory in what I hoped to achieve (basically, it taught the basics of c++ with some very superficial composition patterns).
Question We were told to make our code somewhat object oriented by defining classes for various parts of the code. Since all the parts were very dependent of each other, the general structure looked as follows (basically, a Drive, Sensors and WorldModel class with some dependencies, and a Director class trying to make our robot solve the task at hand)
class Drive{
void update();
Drive(Sensors & sensors);
private:
Sensors & sensors
};
class Sensors{
void update();
}
class WorldModel {
void update();
WorldModel(Sensors & sensors, Drive & drive);
private:
Sensors & sensors;
Drive & drive;
};
class Director {
void update();
Director(Sensors & sensors, Drive & drive, WorldModel & worldmodel);
private:
Sensors & sensors;
Drive & drive;
WorldModel & worldmodel;
};
This is actually an extremely condensed version. It seems to me however that this is not really object oriented code as much as Clumsily Split-Up Codeā¢. In particular, it seemed almost impossible to make e.g. the Sensors class get data from the Drive class without some fudging around in the Director class (i.e., first perform a function in the Drive class to get the velocity setpoint, and then provide that to the update() method in the Sensors class to do some Kalman filtering).
How does one create a project in c++ with various parts being very dependent on each other, without this becoming a problem? I read an SO answer on interfaces but I'm not sure how to apply that to this problem - is that even the way to go here? Is there a design pattern (not necessarily an object oriented one) that is suitable for projects such as this one?
No, there's not a design pattern for projects "like this".
Design patterns are not the goal.
So, let me put a few guesses straight:
Here's what I'd do:
keep unwanted implementation dependencies out of the header file. Optionally use the Pimpl Idiom here.
e.g. if you use library X to implement
Y::frobnicatedon't includelibX.hin yourY.h. Instead, include it inY.cpponly.If you find that you need class member declaration that would require
libX.hin the header, use the Pimpl Idiom.I don't know what else you could want here :)
Maybe, if you need "interfaces" consider using template composition. Policy, strategy, state patterns. E.g. Instead of
You could consider
Which leaves you free to implement
Sensorsin any which way that statically compiles. The "limitation" is that the injection of dependencies needs to be statically defined/typed. The benefit is ultimate flexibility and zero-overhead: e.g. you couldn't have virtual member function templates, but you can use this as aSensorspolicy: