I’d like to design a robust version of this class (C++11):
class Oscillator
{
private:
std::vector<double> trajectory_;
// Some numbers that are needed to get the trajectory
double xinit_;
double vinit_;
double omega_;
public:
Oscillator(double xinit, double vinit, double omega):
xinit_(xinit), vinit_(vinit), omega_(omega) {}
void Integrate(); // Implementation populates 'trajectory_'
// Implementation prints the trajectory in JSON-friendly format
void PrintJSON(std::ostream &);
double TrajectoryMean();
double TrajectoryStdv();
};
Here are some thoughts:
- I’d like to replace the
PrintJSON
method with a private variable of classTrajectoryPrinter
or something, so that I don’t have to changeOscillator::PrintJSON
and recompileoscillator.cpp
everytime there’s a problem - The same goes for the
TrajectoryMean
member. I’d rather have a classTrajectoryStats
that does this for me.
The only problem with the above points is this: both proposed classes require access to a private member of Oscillator
: trajectory_
.
Is there a design pattern or generic design solution to this problem? Is what I am asking for possible?
Thanks.
4
If you want a TrajectoryPrinter
ask for a TrajectoryPrinter
. Right now you’re only asking for doubles.
Something will need to build Oscillator
. Something will need to build TrajectoryPrinter
. I don’t recommend that Oscillator
build or even find TrajectoryPrinter
. Oscillator
shouldn’t know TrajectoryPrinter
as anything except as something it can call a print()
function on.
TrajectoryPrinter
is a dependency. You need one. Just like you need xinit
, vinit
, and omega
. So let someone hand them all to you.
You can do this in main but do this in main a lot and it becomes crowded. It’s ok to create classes whose only job is to build other classes.
This is called simply passing but some people call it dependency injection. The difference is mostly if they’re trying to sell you a framework.
3
If the integrate function is only invoked once per object, what you have is a trajector builder, only it doesn’t expose the trajectory as a first-class entity.
So, you might make a first-class notion of the concept of a trajectory, and have your integrate function be a builder to construct the trajectory entity.
Once you have a first-class trajectory entity, you can pass it around to various other methods, such as serializers, and other manipulators.
2