【问题标题】:Good practice for choosing an algorithm randomly with c++用 c++ 随机选择算法的好习惯
【发布时间】:2010-08-16 14:23:13
【问题描述】:

设置:
必须生成伪随机模式。有几种方法/或算法可用于创建不同的内容。所有算法都会生成一个字符列表(但可以是其他任何字符)......重要的是,它们都返回相同类型的值,并且需要相同类型的输入参数。

必须可以调用 GetRandomPattern() 方法,每次调用时都会使用一种随机算法。

我的第一个方法是将每个算法放在它自己的函数中,并在每次调用 GetRandompattern() 时随机选择其中一个。但是我没有想出另一种在它们之间进行选择的方法,而不是使用不方便、丑陋和不灵活的 switch case 语句。

class PatternGenerator{
 public:
  list<char> GetRandomPattern();
 private:
  list<char>GeneratePatternA(foo bar);
  list<char>GeneratePatternB(foo bar);
  ........
  list<char>GeneratePatternX(foo bar);
}

每次调用 GetRandomPattern() 方法时选择随机 GeneratePattern 函数的好方法是什么?

还是应该对整个班级进行不同的设计?

非常感谢

【问题讨论】:

  • 这正是策略模式的设计目的:-)

标签: c++ design-patterns random function-pointers


【解决方案1】:

为每个算法创建一个类,每个类都是生成器类的子类。将这些对象的实例放入列表中。随机选择一个并使用它!

更笼统地说,如果你开始创建几个具有相同签名的替代方法,那么你就会尖叫“把我们放到同级类中”:)

更新 指针建议出现后,忍不住为面向对象的解决方案多争论了一番

  • 想象一下,您想打印哪个方法创建了哪个随机事物。使用对象很简单,只需添加一个“名称”方法或其他东西。如果你得到的只是一个指针,你想如何实现这一点? (是的,从指向字符串的指针创建一个字典,嗯...)
  • 假设你发现你有十个方法,其中五个只是一个参数不同。所以你写了五个函数“只是为了让代码远离 OOP 垃圾”?或者您不想拥有一个恰好能够存储一些状态的函数(也称为对象?)
  • 我想说的是,这是一些 OOP 设计的教科书应用程序。以上几点只是试图充实这一点,并认为即使它现在可以使用指针,它也不是面向未来的解决方案。而且你不应该害怕编写代码来与读者(即你未来的你,在四个星期左右)交谈,告诉那个人它在做什么

【讨论】:

  • 将成员函数指针放在列表中比将每个指针都包装在一个类中更简单。
  • 好吧,这就是我在 Java 和 C# 而不是 C++ 上花费大部分时间后发生的事情;)但是,由于他已经在使用一个类,我认为值得指出(不是双关语预期)一个合适的 OOP 解决方案应该是什么样子。
  • @nicolas78 您的回答非常合理,但我希望找到一种方法来做到这一点,而无需为每个算法创建一个新类,因为这意味着很多代码行会分散 C++ 中的算法的注意力
  • @Mike Seymour 我将研究成员函数指针。感谢您的建议
  • @nicolas78:确实,如果问题更复杂,那么您的建议可能是最好的方法(尽管在某些情况下函数对象可能会更好)。但是 C++ 是一种多范式语言,如果将每个问题都视为面向对象设计的练习,您将无法从中获得最大收益。
【解决方案2】:

您可以创建一个函数指针数组。这避免了必须创建一大堆不同的类,尽管您仍然必须将函数指针分配给数组的元素。不管你怎么做,都会有很多看起来重复的线条。在您的示例中,它位于 GetRandomPattern 方法中。在我的,它在 PatternGenerator 构造函数中。

#define FUNCTION_COUNT 24
typedef list<char>(*generatorFunc)(foo);

class PatternGenerator{
    public:
        PatternGenerator() {
            functions[0] = &GeneratePatternA;
            functions[1] = &GeneratePatternB;
            ...
            functions[24] = &GeneratePatternX;
        }
        list<char> GetRandomPattern() {
            foo bar = value;
            int funcToUse = rand()%FUNCTION_COUNT;
            functions[funcToUse](bar);
        }
    private:
        generatorFunc functions[FUNCTION_COUNT];
}

【讨论】:

  • 我认为这是最简单的解决方案(尽管使用可以将参数传递给构造函数的函数对象也可以简化事情,如果一堆这些模式生成函数使用具有不同参数的相同算法)。如果您想要一种简单的方法将函数指针和函数对象放在一个数组中,也可以将functions 数组定义为std::tr1::function&lt;list&lt;char&gt;(foo)&gt; functions[FUNCTION_COUNT]
【解决方案3】:

避免类似开关的编码的一种方法是使用策略设计模式。例如:

类 IRandomPatternGenerator { 上市: 虚拟列表 makePattern(foo bar); }; ARandomPatternGenerator 类:公共 IRandomPatternGenerator { 上市: 虚拟列表 makePattern(foo bar) { ... } }; BRandomPatternGenerator 类:公共 IRandomPatternGenerator { 上市: 虚拟列表 makePattern(foo bar) { ... } };

然后您可以根据 RandomPatternGenerator 实例的运行时类型选择特定算法。 (例如创建像 nicolas78 这样的列表)

【讨论】:

    【解决方案4】:

    感谢您的所有宝贵意见。 我决定使用函数指针,主要是因为我以前不知道它们,它们似乎非常强大,这是了解它们的好机会,但也因为它为我节省了很多代码行。

    如果我使用 Ruby / Java / C#,我会决定使用建议的策略设计模式 ;-)

    class PatternGenerator{
     typedef list<char>(PatternGenerator::*createPatternFunctionPtr);
    public:
     PatternGenerator(){
      Initialize();
       }
     GetRandomPattern(){
      int randomMethod = (rand()%functionPointerVector.size());
      createPatternFunctionPtr randomFunction = functionPointerVector.at( randomMethod );
      list<char> pattern = (this->*randomFunction)();
      return pattern;
      }
    private:
      void Initialize(){
       createPatternFunctionPtr methodA = &PatternGenerator::GeneratePatternA;
       createPatternFunctionPtr methodB = &PatternGenerator::GeneratePatternB;
       ...
       functionPointerVector.push_back( methodA );
       functionPointerVector.push_back( methodB );
       }
      list<char>GeneratePatternA(){
       ...}
      list<char>GeneratePatternB(){
       ...}
      vector< createPattern > functionPointerVector;
    

    可读性并没有像设计模式解决方案那样差很多,添加新算法很容易,指针算法封装在一个类中,它可以防止内存泄漏,而且非常快速和有效......

    【讨论】:

    • 最好将指针放在vector 中而不是list 中,这样访问随机元素既快捷又容易。 (randomFunction = functionPointers[randomIndex] 而不是你使用的advance)。
    • 也许这只是一个错字,但随机索引应该是rand() % size(),而不是rand() + size()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-08
    • 2011-11-18
    • 2012-04-12
    • 1970-01-01
    • 2010-10-16
    相关资源
    最近更新 更多