Object-oriented or sequential?

I'm refactoring a 500-lines of C++ code in main() for solving a differential equation. I'd like to encapsulate the big ideas of our solver into smaller functions (i.e. "SolvePotential(...)" instead of 50 lines of numerics code).

Should I code this sequentially with a bunch of functions taking very long parameters lists, such as:

int main(int *argc, void **argv){
   interpolate(x,y,z, x_interp, y_interp, z_interp, potential, &newPotential);
   compute_flux(x,y,z, &flux)
   compute_energy(x,y,z, &eng)
   ...
   // 10 other high-level function calls with long parameter lists
   ...
   return 0;
}

Or should I create a "SolvePotential" class that would be called like so:

int main(int *argc, void **argv){
   potential = SolvePotential(nx, ny, nz, nOrder);
   potential.solve();
   return 0;
}

Where I would define functions in SolvePotential that uses member variables rather than long parameter lists, such as:

SolverPotential::solve(){
  SolvePotential::interpolate()
  SolverPotential::compute_flux()
  SolverPotential::compute_energy()
  // ... 
  //  10 other high-level function calls with NO parameter lists (just use private member variables)
}

In either case, I doubt I'll re-use the code very much... really, I'm just refactoring to help with code clarity down the road.

Maybe this is like arguing "Is it '12' or 'one dozen'?", but what do you think?

Answers


Neither. "Move all my code from one single function to one single class" is not OOP. One of the fundamental rules of OOP is that a class should have one single area of responsibility. This is not a single responsibility, it is around 15:

SolverPotential::solve(){
SolvePotential::interpolate()
SolverPotential::compute_flux()
SolverPotential::compute_energy()
// ... 
//  10 other high-level function calls with NO parameter lists (just use private member variables)
}

It also makes it pretty much impossible to maintain a class invariant, doesn't it? When is it valid to call compute_flux? Solve? Interpolate? What's to stop me from doing it in the wrong order? Will the class be in a valid state if I do? Will I get valid data out of it?

However, why is it an either-or? Why can't you make multiple classes and functions?

// This struct could be replaced with something like typedef boost::tuple<double,double,double> coord3d
struct coord3d {
double x, y, z;
};

coord3d interpolate(const coord3d& coord, const coord3d& interpolated, double potential); // Just return the potential, rather than using messy output parameters
double compute_flux(const coord3d coord&flux); // Return the flux instead of output params
double compute_energy(const coord3d& coord); // And return the energy directly as well

Of course, these functions don't have to be functions. If necessary/convenient, each could be made a class, or probably better still, a functor, to maintain the necessary state, and perhaps to allow you to pass them as arguments to other functions efficiently.

If optimal performance is important, you may have to be careful with directly returning larger structures, rather than using output parameters, but I'd definitely profile first, to see if it is a problem, and even if it is, you could probably avoid output params with expression templates.

If you have an conceptual object on which a number of independent operations can be performed, it's probably a hint that you need some OOP, that it should be modelled as a class with a number of member functions, each of which of course maintain the class invariant, no matter how, when and why they're called.

If you need to compose a number of functions, gluing them together to form new, larger, pieces of functionality, functional programming and functors are most likely what you need. One common reason (but definitely not the only one) to desire composable functions is if you need to perform the same operation on many different sets of data (perhaps even several different types, all implementing the same concept). Making a functor do the heavy lifting allows it to be used with std::transform or std::for_each. You may also want to use currying to gradually assemble your functions (perhaps some of the functions can be parametrized with a set of fixed parameters, which don't vary between calls). Again, create a functor which is initialized with these fixed parameters, and then supply the varying data in operator().

And finally, if you simply need to perform a sequence of operations on some mutable data, plain old procedural programming may be what best suits your needs.

Finally, sprinkle with generic programming, templating the necessary classes and functions to allow them to work together without having to jump through hoops like pointer indirection or inheritance.

Don't get too hung up on OOP. Use the tools at your disposal.

I don't know enough of the context of your question to say for sure, but it seems to me that what you really need isn't a class, it's just a hierarchy of functions. Your user code calls solve(). solve() internally calls, say (made up, for the sake of example), interpolate() and compute_energy(). compute_energy() internally calls compute_flux(), and so on. Each function only makes a couple of calls to perform the logical steps that make up the responsibility of the function. So nowhere do you have a huge class with a dozen different responsibilities, or a big monolithic function which does everything sequentially.

In any case, there is nothing wrong with "very long parameter lists" (You can usually shorten them by grouping some of them together, but even if you can't, there is nothing "un-OOP" about passing a lot of parameters. On the contrary, it means the function is well encapsulated from everything else. All it needs is passed in the parameters, so it isn't really tied to the rest of the application.


Write it sequentially and then refactor if there's something you think you can reuse or would make it clearer.

Also, a SolvePotential class doesn't make a lot of sense since a class should be an Object with the method SolvePotential.


"SolvePotential" is a verb, and classes tend to be nouns with verbs attached. I don't know a lot about the details of your problem, but this may be a sign that a procedural approach would be clearer than OO here. In any case, it certainly seems like if you did create this class, it would be little more than packaging for the functions.

Unless I had a second place to use the class, I'd just declare the functions with explicit arguments - this will be clearer (especially to a new person looking at this code for the first time) than using methods on a class that require hidden state.


Need Your Help

Way to find incremental changes in the system

java postgresql

We have a Java based system with postgres as database. For some reasons we want to propagate certain changes on timely basis (say 1 hour) to a different location. The two broad approaches are

Automate MySQL fields (like Excel)

mysql automation

Say I have a table like ID, NAME, SCORE. Now normally, to get the rankings of the teams, I'd select all and order by. Sometimes though, I don't want to know all the rankings, just the ranking of one

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.