У меня есть алгоритм, который требует большого количества параметров (то есть конфигурации) как часть его конструктора, а также требует некоторых четко определенных этапов создания. Поэтому я создал Образец Строителя реализация, которая позволяет установить необходимые параметры и создать промежуточный и конечный экземпляр, например,
// somewhere
class SomeAlgo {
public:
SomeAlgo(double a, double b, double c, double d, double e /* etc */);
;
Теперь я определяю Строителя как, например.
class SomeAlgoBuilder {
public:
SomeAlgo& createResult() { /* TODO: */ }
virtual SomeAlgoBuilder& creationStep1() = 0;
virtual SomeAlgoBuilder& creationStep2() = 0;
virtual SomeAlgoBuilder& creationStep3() = 0;
// example setter note the builder returns *this
SomeAlgoBuilder& setA(double a) { a_ = a; return *this; }
SomeAlgoBuilder& setB(double b) { b_ = b; return *this; }
// etc
};
На данный момент все выглядит хорошо, но теперь я хотел бы Pull Up
сеттеры строителя в SomeAlgoConfig
класс, так что я также могу охватить сценарий использования передачи простой конфигурации вместо сложного длинного списка параметров. Эта простая конфигурация — это то, что в Java известно как объект значения или бин. Новый Строитель будет выглядеть так:
// not "is a" config but need the implementation inheritance
// >>>>>> note the need to pass SomeAlgoBuilder as template
class SomeAlgoBuilder : private SomeAlgoConfig<SomeAlgoBuilder> {
public:
SomeAlgo& createResult() { /* TODO: */ }
virtual SomeAlgoBuilder& creationStep1() = 0;
virtual SomeAlgoBuilder& creationStep2() = 0;
virtual SomeAlgoBuilder& creationStep3() = 0;
};
Теперь SomeAlgoConfig
реализация:
template<T>
class SomeAlgoConfig {
T& setA(double a) { a_ = a; return *static_cast<T*>(this); }
T& setB(double b) { b_ = b; return *static_cast<T*>(this); }
// etc
}
и намерение должно быть использовано так:
SomeAlgoConfig config; // <<< here it won't compile because it misses the T parameter
config.setA(a).setB(b).setC(c);
Я думаю, это поможет. Однако всякий раз, когда я хотел бы использовать SomeAlgoConfig
самостоятельно (вне контекста строителя), например чтобы передать его в качестве параметра, мне нужно объявить его с параметром шаблона, который был бы сам SomeAlgoConfig<SomeAlgoConfig>
, Как я могу определить его так, чтобы он по умолчанию использовался как тип шаблона? например делать это не работает: template<typename T = SomeAlgoConfig> class SomeAlgoConfig
поскольку SomeAlgoConfig
на данный момент еще не известно.
Config должен быть похож на контейнер для параметров, поэтому вам не нужно менять конструкторы и установщики всякий раз, когда вы передумаете о параметрах, которые хотите передать. Делать сборку наследником конфигурации не имеет смысла, потому что строитель не является конфигурацией, а «Мне нужны унаследованные методы» не является допустимым аргументом для реализации этого в вашем проекте. Вы можете сделать конфиг членом сборщика и вызвать:
builder.getConfig().setA(a);
builder.getConfig().setB(b);
//...
builder.createResult();
Если вы хотите иметь конфигурацию шаблона, вы бы также сделали шаблон компоновщика, например:
template<class T>
class AlgoBuilder<T>{
//...
private:
AlgoConfig<T> config;
Таким образом, вы можете установить pass config в конструкторе.
По поводу вашего вопроса об отсутствии параметра T при создании экземпляра конфигурации … Ну, на этом этапе, так как вы хотите установить a, b, c и все другие параметры, вы уже знаете тип параметров, так что вы можете фактически создать экземпляр Конфиг с типом T, который является тем же типом ваших параметров. AlgoConfig< AlgoConfig> не имеет для меня особого смысла.
Других решений пока нет …