Strategy pattern or function pointer [closed]

2019-08-12 08:41发布

In C++ when I have algorithm which could accept different behaviour in runtime I rather use function pointer.

For example, a program for drawing charts has one algorithm to draw line which can accept any function to specialize shape of this line.

In Java there are no function pointers and I am obliged to use either the strategy pattern or reflection (or another pattern).

How to to enable special behavior to be selected at runtime in my programme? Strategy pattern either function pointer?

3条回答
Viruses.
2楼-- · 2019-08-12 09:16

There are multiple ways to implement the strategy pattern in C++.

  1. Use the OOP method like in other programming languages.
  2. Use a function object.
  3. Use a policy class.

All three can get the job done so which one to choose highly depends on your problem.

You mentioned that you want to use a strategy to draw a diagram. This is a complex use-case in my opinion and you shall go with option one, because your strategy object may query settings like preferred colors and so on and you may want to store the strategies somewhere, such that the user can select them in a combo-box.

A function object is really nice if you want to give the clients (your co-workers) a lot of flexibility. In my current project we use function objects for stop-criterion testing in an algorithm. This is very nice with lambdas in C++11 as long as the functionality does not become too complex.

The policy base way may be the fastest but it needs to know the type at compile-time. No DLLs base plugins when using this. At least not until you encapsulate your implementation in a class hierarchy:

template <class LockPolicy>
class MyClass
{
  void do_something()
  {
    LockPolicy::lock();
    //...
    LockPolicy::unlock();
  }
};

I think good advices are:

  • Use 1. if the strategy is complex and may query other systems.
  • Use 1. if you want new strategy implementations by a plug-in
  • Use 2. if the strategy can be expressed in short code lines
  • Use 2. if the strategy implementations fit free functions and you dont want to introduce a class hierarchy
  • Use 3. if you really know what you are doing and you need the performance.
查看更多
祖国的老花朵
3楼-- · 2019-08-12 09:19

In Java function pointers are implemented using functors. Create an interface with one function and pass instances of it instead of function pointers. Let's your code in C++ looked like:

void func(void (*f)(int par));

In Java this would look like:

public interface F {
  public void f(int par);
}

void func(F f);

Take a look at Guava's Function class. This is also not a bad approach for C++ as well. It is more readable and allows user to pass in objects with state as opposed to static functions.

查看更多
一纸荒年 Trace。
4楼-- · 2019-08-12 09:29

It depends entirely on what you are doing with your functor. If you want to use it as a one-off to do an operation, you want to use a template. As an example, see any of the standard algorithms - say, std::sort:

template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );
                                          ^^^^^^^^^^^^
                                          any functor that does comparing

If you want to store your functors for use later, you want std::function - a type-erased functor:

class SaveFunctionForLater {
public:
    template <typename F>
    SaveFunctionForLater(F&& f)
        : func(std::forward<F>(f))
        { }

    int callMe(int i) { return func(i); }
                               ^^^^
                               use the saved one

private:
    std::function<int(int)> func; // function taking an int, returning an int
};

Which you would use like:

int f(int i) { return 2*i; }

template <int I>
struct Constant {
    int operator()(int ) { return I; }
};

SaveFunctionForLater add1([](int i){return i+1;});    // works with lambda
SaveFunctionForLater double(f);                       // works with func ptr
SaveFunctionForLater zero(Constant<0>{});             // works with object

cout << add1.callMe(2);                  // prints 3
cout << double.callMe(double.callMe(4)); // prints 16
cout << zero.callMe(42);                 // prints 0

You definitely don't want to use explicit function pointers - that will severely limit the usability of your class/function. You want to allow people to pass in objects too. This is, after all, C++ and not C!

查看更多
登录 后发表回答