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

#c #algorithm #design-patterns #function #parameters

#c #алгоритм #шаблоны проектирования #функция #параметры

Вопрос:

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

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

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

Вместо этого у меня есть класс, Algorithm который содержит алгоритмы, и у меня есть структура AlgorithmGlobals , которая содержит эти параметры. Я либо передаю эту структуру в:

 void runAlgorithm(AlgorithmGlobals const amp; 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:

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

Ответ №2:

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

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:

У вас есть несколько разных идей, которые вы должны предложить в своем дизайне:

  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 amp;params) : params_(params) { }

    void run();

  private:
    const Parameters params_; // Paramaeters don't change while algorithm
};                            // is running. 
  

Это то, что я бы предложил.

Комментарии:

1. Отличный ответ. Я немного новичок в StackOverflow, и сейчас сижу, смотрю на несколько отличных ответов и задаюсь вопросом, какой из них выбрать в качестве ответа, лол. Этот шаблон настолько понятен и хорошо описан! 😉

2. @Lex Fridman — Я бы передал параметры в вызов функции, за исключением того, что вы назвали свой класс ‘Algorithm’, что подразумевает, что это в основном инкапсуляция запуска вашего алгоритма. Кроме того, мне пришлось отредактировать, поскольку я понял, что объявление params_ было незаконным, если только определение Parameters не находилось внутри класса. И спасибо! 🙂

3. STL часто использует этот подход в своей реализации.

Ответ №4:

Я использую этот метод, о котором вы уже упоминали:

 void runAlgorithm(AlgorithmGlobals const amp; globals);
  

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

Ответ №5:

Здесь может быть полезна идиома именованных параметров.

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

Ответ №6:

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

 class Algorithm {
public:
Algorithm::Algorithm(AlgorithmGlobals const amp; globals) : globals_(globals) {}

    void runAlgorithm(); // use globals_ inside this function

   private:
    const AlgorithmGlobals globals_;
    };
  

Теперь вы можете использовать его как таковой:

 AlgorithmGlobals myglobals;
myglobals.somevar = 12;

Algorithm algo(myglobals);
  

Комментарии:

1. Это мое любимое решение. За исключением того, что, поскольку в OP говорится, что параметры остаются постоянными во время выполнения алгоритма, я бы сделал это const AlgorithmGlobals _globals; . Кроме того, в стандарте C зарезервированы начальные символы подчеркивания. Используйте завершающий символ подчеркивания (т.Е. globals_ не _globals ).

2. _globals в данном контексте не зарезервирован.