Шаблон проектирования С++ для передачи большого количества параметров

У меня есть класс разумного размера, который реализует несколько логически связанных алгоритмов (из теории графов). В качестве входа в алгоритм требуется около 10-15 параметров. Они не модифицируются алгоритмом, а используются для управления его работой. Во-первых, я объясню два варианта реализации этого. Мой вопрос - это общий способ сделать это (независимо от того, является ли он или нет одним из двух вариантов).

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

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

Вместо этого у меня есть класс Algorithm, который содержит алгоритмы, и у меня есть struct 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(). Нет необходимости "защищать" их.

Ответы

Ответ 1

Это называется "Объект параметра" , и это вообще хорошо. Мне не нравится версия участника, особенно называя ее "XGlobals" и подразумевая, что она поделена повсюду. Вместо этого шаблон объекта параметров обычно включает создание экземпляра объекта параметра и передачу его в качестве параметра вызова функции.

Ответ 2

Другие упомянули объект Parameter, но есть и другая возможность: используя Builder.

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();

Ответ 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. 

Вот что я хотел бы предложить.

Ответ 4

Я использую эту технику, о которой вы уже говорили:

void runAlgorithm(AlgorithmGlobals const & globals);

Но вместо этого вызывается класс AlgorithmParams.

Ответ 6

Почему бы вам не сделать это:

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