【问题标题】:C++ Strategy patternC++ 策略模式
【发布时间】:2011-09-06 18:32:24
【问题描述】:

过去,我曾将策略模式解释为一种机制,它允许函数/类的用户为该函数/类提供他们自己的功能。

我一直被教导,实现该模式的方法是将函数指针放入您的类/函数并在内部调用它们,从而允许程序员提供他们自己的“策略”,这些“策略”将在这些函数内部使用,并且对象。

最近环顾四周,我发现策略模式似乎总是通过使用继承层次结构来解释/定义,如下所示:

Strategy pattern implementation

这是意见/实现的差异,还是函数指针传递不是策略模式的变体?我最感兴趣,所以当我评论或解释我的代码时,我不会让人们感到困惑:)

【问题讨论】:

  • 有人只是对这个问题投了反对票,两个答案都没有 cmets...我有时讨厌别人:p
  • 是的。我标记了这个问题,我们会看看是否有一个模组会来修复它。
  • 这里没有不规则的投票模式。从旗帜来看,我完全相信有人飞过并开始点击投票。由于这是一个罕见的“良好主观”(恕我直言)的例子,而且我确实使用 C++(至少足以理解这个问题),我倾向于点击几次投票。如果再次发生这种情况,请标记,我会请开发人员调查一下。
  • 谢谢大家,非常有启发性的答案:)

标签: c++ design-patterns strategy-pattern


【解决方案1】:

你只需要在没有函数指针的语言中使用继承(阅读:Java)。

就我个人而言,我更喜欢 std::function 而不是原始函数指针,因为它接受更广泛的参数并允许您在策略对象中维护状态。

此外,如果您在编译时就已经知道策略,您甚至可以使用模板,从而节省函数指针和std::function 对象的空间和运行时开销。

【讨论】:

  • 或者:你必须在没有对象的语言中使用函数指针!
  • @Ernest:和往常一样,C++ 给你一个选择。我只是在列出可能性,所以 w00te 可以做出明智的选择。不幸的是,一些设计模式的权威人士不同意,并立即投票给我。
  • 看起来他同时否决了这个问题和所有三个答案——我已经请了主持人。
  • std::function 与裸函数指针的选择表明策略对象可以具有状态。这是使用接口的真正要点:策略对象可以维护变量,函数指针不能。
  • 那么提供函子/函数对象作为参数是否适合替代继承层次结构?那可能有状态:)
【解决方案2】:

在我看来,使用函数指针实现策略模式是在不支持 OOP 的语言(例如 C)中完成的。

在支持 OOP 的语言中,使用类更好地实现它:继承、虚函数(即运行时多态性)、接口等。通常,这是运行时策略模式,也就是说,您可以在运行时切换到其他策略模式来改变程序的行为。

在 C++ 中,还有一种编译时策略模式,俗称policy-based design

在任何情况下,类都可以维护状态,而函数指针则不能。这是使用类的最大优势。

【讨论】:

  • 一位天才对每个人都投了反对票,没有留下任何评论。
  • 我投了赞成票以取消它。感谢您的回答,我会在 15 分钟内挑选出最好的 :)
【解决方案3】:

使用函数指针来实现策略是基于继承的版本的退化情况。如您所知,该模式的基本内核是能够在运行时提供或修改某个进程的组件。该组件可以是一个函数,也可以是一个对象。如果策略由几个位组成,那么基于继承的版本确实更好,因为一个对象可以将多个方法封装在一起;如果只有一块,那么函数指针就差不多了。

【讨论】:

    【解决方案4】:

    接口对象可以有状态,因此可以维护成员变量。函数指针不能。

    【讨论】:

      【解决方案5】:

      IMO,starategy 模式可以使用:

      • 模板和编译时常量表达式(早期绑定,实际上可能不称为 strategy-pattern)。
      • 虚拟函数机制(是的,通过将不同的派生类分配给引用/指针)。
      • 函数指针
      • 指向类的成员(方法)。
      • 使用 std::function 和 lambdas。

      【讨论】:

        【解决方案6】:

        这是一个实用的c++策略模式代码。我希望纯虚拟函数的使用(而不是 Java 中的接口)是不言自明的。

        #include <iostream>
        #include <fstream>
        #include <string.h>
        
        using namespace std;
        
        class Strategy;
        
        class TestBed{
          public:
            TestBed(){
                myStrategy = NULL;
            }
            void setBehavior(int type);
            Strategy *myStrategy;
        };
        
        class Strategy{
          public:
            void performBehavior(){
               behave();
            }
          private:
            virtual void behave() = 0;
        };
        
        class behaviorOne: public Strategy{
          private:
            void behave(){
                cout << "left strategy" << endl;
            }
        };
        
        class behaviorTwo: public Strategy{
          private:
            void behave(){
                cout << "right strategy" << endl;
            }
        };
        
        class behaviorThree: public Strategy{
          private:
            void behave(){
                cout << "center strategy" << endl;
            }
        };
        
        void TestBed::setBehavior(int type){  
          delete myStrategy;
          if (type == 0)
            myStrategy = new behaviorOne();
          else if (type == 1)
            myStrategy = new behaviorTwo();
          else if (type == 2)
            myStrategy = new behaviorThree();
        }
        
        int main(){
          TestBed test;
          int answer;  
          while(1){
             cout << "Exit(other) Left(0) Right(1) Center(2): ";
             cin >> answer;
             if(answer > 2) break;
             test.setBehavior(answer);
             test.myStrategy->performBehavior();
          }   
          return 0;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-09-15
          • 1970-01-01
          相关资源
          最近更新 更多