views:

296

answers:

6

I'm wondering how (un)common it is to encapsulate an algorithm into a class? More concretely, instead of having a number of separate functions that forward common parameters between each other:

void f(int common1, int param1, int *out1);
void g(int common1, int common2, int param1, int *out2)
{
  f(common1, param1, ..);
}

to encapsulate common parameters into a class and do all of the work in the constructor:

struct Algo
{
  int common1;
  int common2;

  Algo(int common1, int common2, int param)
  { // do most of the work }

  void f(int param1, int *out1);
  void g(int param1, int *out2);
};

It seems very practical not having to forward common parameters and intermediate results through function arguments.. But I haven't seen this "pattern" being widely used.. What are the possible downsides?

A: 

If you would ever need to call both methods with the constructor parameters then i would do it.

If you would never need to call both methods with the same parameters then I wouldn't.

ctrlShiftBryan
+4  A: 

There's a design pattern that addresses the issue; it's called "Strategy Design Pattern" - you can find some good info on it here.

The nice thing about "Strategy" is that it lets you define a family of algorithms and then use them interchangeably without having to modify the clients that use the algorithms.

Esteban Araya
+1  A: 

I usually create a functor or Function Object to encapsulate my algorithms.

I usually use the following template

class MyFunctor {
    public:
       MyFunctor( /* List of Parameters */ );
       bool execute();
    private:
       /* Local storage for parameters and intermediary data structures */
}

Then I used my functors this way:

    bool success = MyFunctor( /*Parameter*/ ).execute();
David Segonds
I would expect a function object to execute using operator()
andreas buykx
+4  A: 

It's not a bad strategy at all. In fact, if you have the ability in your language (which you do in C++) to define some type of abstract superclass which defines an opaque interface to the underlying functionality, you can swap different algorithms in and out at runtime (think sorting algorithms, for example). If your chosen language has reflection, you can even have code that is infinitely extensible, allowing algorithms to be loaded and used that may not have even existed when the consumer of said algorithms was written. This also allows you to loosely couple your other functional classes and algorithmic classes, which is helpful in refactoring and in keeping your sanity intact when working on large projects.

Of course, anytime you start to build a complex class structure, there will be extra architecture - and therefore code - that will need to be built and maintained. However, in my opinion the benefits in the long run outweigh this minor inconvenience.

One final suggestion: do not do your work in the constructor. Constructors should only be used to initialize a classes internal structure to reasonable defaults. Yes, this may include calling other methods to finish initialization, but initialization is not operation. The two should be separate, even if it requires one more call in your code to run the particular algorithm you were looking for.

rpj
+1  A: 

Perhaps a better approach (unless I'm missing something) is to ecapsualte the algorithm in a class and have it execute through a method call. You can either pass in all the parameters to public properties, through a constructor, or create a struct that ecapsulates all the parameters that gets passed in to a class that contains the algorithm. But typically it's not a good idea to execute things in the constructor like that. First and foremost because it's not intuitive.

public class MyFooConfigurator
{
   public MyFooConfigurator(string Param1, int, Param2) //Etc...
   {
      //Set all the internal properties here
      //Another option would also be to expose public properties that the user could
      //set from outside, or you could create a struct that ecapsulates all the
      //parameters.
      _Param1 = Param1; //etc...
    }

    Public ConfigureFoo()
    {
       If(!FooIsConfigured)
          return;
       Else
          //Process algorithm here.
    }
}
Micah
+1  A: 

Could your question be more generally phrased like, "how do we use object oriented design when the main idea of the software is just running an algorithm?"

In that case, I think that a design like you offered is a good first step, but these things are often problem-dependent.

I think a good general design is like what you have there. . .

class InputData {};
class OutputData {};

class TheAlgorithm 
{
private:
     //functions and common data

public:
   TheAlgorithm(InputData);      
   //other functions
   Run();
   ReturnOutputData();
};

Then, let that interact with the main() or your GUI however you want.

Baltimark