Шаблон проектирования С++ для передачи большого количества параметров
У меня есть класс разумного размера, который реализует несколько логически связанных алгоритмов (из теории графов). В качестве входа в алгоритм требуется около 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 ¶ms) : params_(params) { }
void run();
private:
const Parameters params_; // Paramaeters don't change while algorithm
}; // is running.
Вот что я хотел бы предложить.
Ответ 4
Я использую эту технику, о которой вы уже говорили:
void runAlgorithm(AlgorithmGlobals const & globals);
Но вместо этого вызывается класс AlgorithmParams
.
Ответ 5
Именованный идентификатор параметров может быть полезен здесь.
a.runAlgorithm() = Parameters().directed(true).weight(17).frequency(123.45);
Ответ 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);