传递大量参数的c++设计模式

C++ Design Pattern for Passing a Large Number of Parameters

本文关键字:c++ 设计模式 参数      更新时间:2023-10-16

我有一个合理大小的类,它实现了几个逻辑相关的算法(来自图论)。大约需要10-15个参数作为算法的输入。这些不被算法修改,而是用来指导算法的运行。首先,我将解释实现此功能的两个选项。我的问题是这样做的常见方法是什么(无论它是或不是两个选项之一)。

N很大时,我个人不喜欢将这些值作为参数传递给函数,特别是当我还在开发算法时。

void runAlgorithm(int param1, double param2, ..., bool paramN);

我有一个包含算法的类Algorithm,我有一个包含这些参数的结构体AlgorithmGlobals。我将这个结构体传递给:

void runAlgorithm(AlgorithmGlobals const & globals);

或者我添加一个公共AlgorithmGlobals实例到类:

class Algorithm {
public:
    AlgorithmGlobals globals;
    void runAlgorithm();
}

那么在其他地方我将这样使用:

int main() {
    Algorithm algorithm;
    algorithm.globals.param1 = 5;
    algorithm.globals.param2 = 7.3;
    ...
    algorithm.globals.paramN = 5;
    algorithm.runAlgorithm();
    return 0;
}

注意,AlgorithmGlobals的构造函数为每个参数定义了良好的默认值,因此只需要指定具有非默认值的参数。

AlgorithmGlobals不是私有的,因为它们可以在runAlgorithm()函数被调用之前被自由地修改。没有必要"保护"他们。

这被称为"参数对象"模式,这通常是一件好事。我不喜欢成员版本,特别是称它为"XGlobals",并暗示它是到处共享的。相反,参数对象模式通常涉及创建参数对象的实例,并将其作为参数传递给函数调用。

其他人已经提到参数对象,但是还有另一种可能性:使用生成器

Builder允许省略默认值合适的参数,从而简化代码。如果你要用几个不同的参数集来使用你的算法,这是特别方便的。OTOH还允许重用类似的参数集(尽管存在无意重用的风险)。这(连同方法链)将允许您编写诸如

这样的代码
Algorithm.Builder builder;
Algorithm a1 = builder.withParam1(1).withParam3(18).withParam8(999).build();
...
Algorithm a2 = builder.withParam2(7).withParam5(298).withParam7(6).build();

你应该在你的设计中提出几个不同的想法:

  1. 参数为纯输入。
  2. 这些参数是针对你的算法的。
  3. 各参数默认值相同。

class Algorithm {
  public:
    class Parameters { // Nested class, these are specific to your algorithm.
      public:
        Parameters() : values(sensible_default) { }
        type_t values; // This is all about the data.
    };
    Algorithm(const Parameters &params) : params_(params) { }
    void run();
  private:
    const Parameters params_; // Paramaeters don't change while algorithm
};                            // is running. 

这就是我的建议

我使用您已经提到的技巧:

void runAlgorithm(AlgorithmGlobals const & globals);

但是会把这个类命名为AlgorithmParams

命名参数习惯用法在这里可能有用。

a.runAlgorithm() = Parameters().directed(true).weight(17).frequency(123.45);

建议为什么不这样做呢:

class Algorithm {
public:
Algorithm::Algorithm(AlgorithmGlobals const & globals) : globals_(globals) {}
    void runAlgorithm(); // use globals_ inside this function
   private:
    const AlgorithmGlobals globals_;
    };

现在你可以这样使用:

AlgorithmGlobals myglobals;
myglobals.somevar = 12;
Algorithm algo(myglobals);