1

В C++, когда у меня есть алгоритм, который может принимать разные действия во время выполнения, я скорее использую указатель на функцию.Стратегический шаблон или указатель функции

Например, программа для рисования диаграмм имеет один алгоритм для рисования линии, который может принимать любую функцию для специализации формы этой строки.

В Java нет указателей на функцию, и я обязан использовать либо шаблон стратегии, либо отражение (или другой шаблон).

Как включить специальное поведение для выполнения во время выполнения в моей программе? Стратегический шаблон либо указатель на функцию?

+0

Внесите * что * "операция"? Что вы считаете «лучшим» (это очень субъективное слово)? Каков ваш прецедент? –

+0

Я имею в виду операцию, которая позволяет выбирать поведение алгоритма во время выполнения. – ElConrado

+0

C++ 11? См. Lambdas и 'std :: function <>' –

ответ

2

В указателях функций Java реализованы с использованием функторов. Создайте интерфейс с одной функцией и передайте ему экземпляры вместо указателей на объекты. Давайте ваш код в C++ выглядел как:

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

В Java это будет выглядеть так:

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

void func(F f); 

Посмотрите на Function класса гуавы в. Это также не плохой подход для C++. Это более читаемо и позволяет пользователю передавать объекты с состоянием в отличие от статических функций.

+0

Правильно ли это использовать его вместо шаблона стратегии? Интересно, что лучше. – ElConrado

+2

Это довольно шаблон стратегии. F - это ваш стратегический интерфейс, и его подклассы являются фактическими стратегиями. –

1

Это зависит полностью от того, что вы делаете с вашим функтором. Если вы хотите использовать его как одноразовое для выполнения операции, вы хотите использовать шаблон . В качестве примера см любого из стандартных алгоритмов - скажем, std::sort:

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

Если вы хотите сохранить ваши функторы для последующего использования, вы хотите std::function - типа стертого функтора:

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 
}; 

что вы будете использовать, как:

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 

вы определенно не хотите использовать явные указатели на функции - которые будут строго ограничить использование вашего класса/функции. Вы хотите, чтобы люди тоже проходили объекты. Это, в конце концов, C++, а не C!

+0

Хорошо, спасибо. Я хочу сохранить функцию, которая используется для рисования диаграммы внутри моей программы, поэтому в данном случае не рекомендуется использовать указатели? – ElConrado

+0

@ ElConrado Вы * можете * хранить указатель на функцию, но только для фактической функции (свободной или 'статической'). Но если вы используете 'std :: function', вы можете использовать * any * callable. Это сделает ваш класс более полезным. – Barry

2

Существует несколько способов реализации шаблона стратегии на C++.

  1. Используйте метод ООП, как на других языках программирования.
  2. Используйте объект функции.
  3. Используйте класс политики.

Все трое могут выполнить свою работу так, чтобы выбрать, сильно зависит от вашей проблемы.

Вы упомянули, что хотите использовать стратегию для рисования диаграммы. На мой взгляд, это сложный прецедент, и вы пойдете с вариантом один, потому что ваш объект стратегии может запрашивать настройки, такие как предпочтительные цвета, и так далее, и вы можете захотеть сохранить стратегии где-нибудь, чтобы пользователь мог выбрать их в поле со списком.

Функциональный объект действительно хорош, если вы хотите предоставить клиентам (вашим коллегам) большую гибкость.В моем текущем проекте мы используем функциональные объекты для тестирования стоп-критерия в алгоритме. Это очень хорошо с lambdas в C++ 11, пока функциональность не становится слишком сложной.

Путь к политике может быть самым быстрым, но он должен знать тип во время компиляции. При использовании этого модуля не поддерживаются DLL. По крайней мере, пока вы не инкапсулировать реализацию в иерархии классов:

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

Я думаю, что хорошие советы являются:

  • Использование 1. Если стратегия является сложной и может запросить другие системы.
  • Использование 1. Если вы хотите новые реализаций стратегии от плагина в
  • Использования 2. если стратегия может быть выражены в коротких строках кода
  • Использование 2. Если реализации стратегий подходят свободные функции и вы не хотите ввести иерархию классов
  • Используйте 3. если вы действительно знаете, что делаете, и вам нужна производительность.
Смежные вопросы