简体   繁体   English

如何用std :: function在C ++中实现策略模式

[英]How to implement strategy pattern in C++ with std::function

I'm reasing about the best way to implement the strategy pattern in C++. 我正在讨论在C ++中实现策略模式的最佳方法。 Up to now, I've always used the standard way, where the context has a pointer to the base strategy class as follows: 到目前为止,我一直使用标准方式,其中上下文具有指向基本策略类的指针,如下所示:

 class AbstractStrategy{
 public:
     virtual void exec() = 0;
 }
 class ConcreteStrategyA{
 public:
     void exec();
 }
 class ConcreteStrategyB{
 public:
     void exec();
 }

 class Context{
 public:
     Context(AbstractStrategy* strategy):strategy_(strategy){}
     ~Context(){
          delete strategy;
       }
      void run(){
           strategy->exec();
      }
 private:
     AbstractStrategy* strategy_;

Since having pointers to objects can result in bad behavior, I was looking for a safer way to implement this pattern and I found this question where std::function are proposed as a better way to handle this pattern. 由于有指向对象的指针可能导致不良行为,我一直在寻找一种更安全的方式来实现这种模式,我发现这个问题 ,其中std::function被提议作为处理这种模式的更好方法。

Could someone please explain better how std::function works, maybe with an example with the strategy pattern? 有人可以更好地解释std::function是如何工作的,也许有一个战略模式的例子?

Note that single-method objects are isomorphic to functions, and strategies are just single-method objects. 请注意,单方法对象与函数同构,而策略只是单方法对象。

So basically, you get rid of all your classes, and you just use std::function<void()> instead: 所以基本上,你摆脱了所有的类,你只需使用std::function<void()>

class Context {
public:
    template<typename F>
    explicit Context(F strategy) : strategy(std::move(strategy)) { }

    void run() { strategy(); }

private:
    std::function<void()> strategy;
};

Then you can pass any callable to the constructor of Context : 然后你可以将任何callable传递给Context的构造函数:

Context ctx([] { std::cout << "Hello, world!\n"; });
ctx.run();

There's a bit of a discussion of this topic here and here . 这里这里有一些关于这个主题的讨论。 I think it depends on the particular case at hand. 我认为这取决于手头的具体情况。 Is your strategy a simple function call only, for instance - I often have strategy patterns in which my strategy will need multiple capabilities, which isn't handled well by just having a function or functor. 例如,你的策略只是一个简单的函数调用 - 我经常有策略模式,我的策略需要多个功能,只需要一个函数或函子就不能很好地处理。 But if you do need just a function or functor, then std::function is a handy way to allow ultimate flexibility, storing function pointers, lambdas or functors. 但是如果你确实只需要一个函数或函子,那么std::function是一种方便的方法,可以实现最大的灵活性,存储函数指针,lambdas或functor。 There can be performance issues, which were discussed here for the original boost implementation. 可能存在性能问题, 这里讨论了原始的boost实现。

Working on the answer of райтфолд 研究райтфолд的答案

Basically, you get rid of all your classes, and you just use std::function instead. 基本上,你摆脱了所有的类,你只需使用std :: function。

This generalized function allows you to pass functions, lambda, functors, and member functions (using std::bind) 这个通用函数允许您传递函数,lambda,仿函数和成员函数(使用std :: bind)

class Context {
public:
   explicit Context(std::function<void()> input) : strategy(input) { }

void run() { strategy(); }

private:
   std::function<void()> strategy;
};

Then you can pass any callable to the constructor of Context: 然后你可以将任何callable传递给Context的构造函数:

Context ctx([] { std::cout << "Hello, world!\n"; });
ctx.run();

or 要么

void sayHelloWorld(){
   std::cout << "Hello, world!\n";
}


int main(){
   Context ctx( sayHelloWorld );
   ctx.run();  
}

or 要么

class SayHelloWorld{
   operator()(){std::cout << "Hello, world!\n";}
}

int main(){
   SayHelloWorld hello_world;
   Context ctx( hello_world );
   ctx.run();  
}

Something like this ? 像这样的东西?

#include <functional>
#include <iostream>


typedef std::function<int(int)> Strategy;

void execute_strategy(Strategy strategy, int object) {
    std::cout << strategy(object) << std::endl;
};

int power2(int i) {
    return i*i;
};

int main() {
    execute_strategy(power2, 3);
}

I mean, strategy pattern is a solution for the shortcoming of not having actual lambdas. 我的意思是,策略模式是解决没有实际lambda的缺点。 That's resolved, so you could just pass the appropriate function around. 这已经解决了,所以你可以通过相应的函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM