Design classes to prevent future code breaks

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:

  1. I’d like to replace the PrintJSON method with a private variable of class TrajectoryPrinter or something, so that I don’t have to change Oscillator::PrintJSON and recompile oscillator.cpp everytime there’s a problem
  2. The same goes for the TrajectoryMean member. I’d rather have a class TrajectoryStats 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

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *