C++ 通过构造函数注入 'strategies'
C++ injecting 'strategies' through constructor
我正在开发一些需要确定 'steps' 的复杂计算(策略模式类型实现),我不确定将步骤子计算 classes 注入的最佳方法主要 class.
我研究过基于策略的设计,但读到策略设计是针对 'compile time polymorphism' 而不是运行时的。另外,我不确定如何使用模板,因为某些子计算 classes 需要构造函数参数。
我已经开始为每个步骤实现虚拟 'interface' classes 并在构造函数中将每个步骤作为 unique_ptr 注入,但不确定这是否正确 'modern C++'方式。
我最初开始在主要 class 中实现所有功能,但发现这使得独立地对每个步骤进行单元测试变得困难甚至不可能。
结构类似于下面:
class CalculationStepA
{
public:
// default constructor
StepAResult performStep(const input& requiredInput);
};
class CalculationStepBType1
{
public:
// default constructor
StepBResult performStepB(const stepBInput& requiredInput);
};
class CalculationStepBType2
{
public:
CalculationStepBType2(const inputIOnlyNeedForType2& parameters)
{
// initialize class members from input
// need for this calculation type
}
StepBResult performStepB(const stepBInput& requiredInput);
};
class CalculationStepCType1
{
public:
CalculationStepBType2(const inputIOnlyNeedForType1& parameters)
{
// initialize class members from input
// need for this calculation type
}
StepCResult performStepC(const stepCInput& requiredInput);
};
class CalculationStepCType2
{
public:
CalculationStepBType2(const inputIOnlyNeedForType2& parameters)
{
// initialize class members from input
// need for this calculation type
}
StepCResult performStepB(const stepCInput& requiredInput);
};
class ClassThatUsesAllTheCalculations
{
public:
ClassThatUsesAllTheCalculations(/* take required parameters that determine which step types I need */)
{}
// possible constructor?
ClassThatUsesAllTheCalculations(
std::unique_ptr<IStepACalculationStrategy> stepA,
std::unique_ptr<IStepBCalculationStrategy> stepB,
std::unique_ptr<IStepCCalculationStrategy> stepC)
{
}
FinalResult executeCalculation(const finalInputRequiredHere& input)
{
auto stepAresult = stepACalculator(somethingFromInput);
// logic to use stepA and determine if we should continue
auto stepBresult = stepBCalculator(somethingFromStepAResult);
// again, logic to use stepB and determine if we should continue
auto stepCresult = stepCCalculator(somethingFromStepBResult);
// assemble final result
return theFinalResult
}
// other method needed to setup calculation
private:
TypeForStepACalculation stepACalculator;
TypeForStepBCalculation stepBCalculator;
TypeForStepCCalculation stepCCalculator;
};
如果能帮助确定最佳设计,我们将不胜感激。
什么是简单的继承?
struct StepA{
virtual StepAResult perform(StepAParams)=0;
};
struct someStepAImpl : public StepA{
virtual StepAResult perform(StepAParams params) override {
//actual implementation
}
};
你的计算 class 是否使用引用(必须在构造时设置)、std::reference_wrapper
(不为空,但可以稍后更改)或某种(智能)指针(可能是 nullptr
,不要忘记检查它,但在管理生命周期时最简单)取决于您计划如何使用它以及您希望如何管理对象的生命周期。像您一样使用 unique_ptr
的示例是:
class Calculator
{
public:
Calculator(
std::unique_ptr<StepA> stepA,
std::unique_ptr<StepB> stepB,
std::unique_ptr<StepC> stepC
)
:m_stepA(std::move(stepA)),m_stepB(std::move(stepB)),m_stepC(std::move(stepC))
{}
FinalResult executeCalculation(const finalInputRequiredHere& input)
{
//logic
auto stepAresult = stepA->perform(StepAParams);
//logic
auto stepBresult = stepB->perform(StepBParams);
//logic
auto stepCresult = stepC->perform(StepAParams);
//logic
return FinalResult();
}
private:
std::unique_ptr<StepA> m_stepA=nullptr;
std::unique_ptr<StepB> m_stepB=nullptr;
std::unique_ptr<StepC> m_stepC=nullptr;
};
void somewhereElse(){
std::unique_ptr<StepA> stepa(new someStepAImpl());
std::unique_ptr<StepB> stepa(new someStepBImpl());
std::unique_ptr<StepC> stepa(new someStepCImpl());
Calculator calc(
std::move(stepa),
std::move(stepb),
std::move(stepc)
);
calc.executeCalculation(...);
}
我正在开发一些需要确定 'steps' 的复杂计算(策略模式类型实现),我不确定将步骤子计算 classes 注入的最佳方法主要 class.
我研究过基于策略的设计,但读到策略设计是针对 'compile time polymorphism' 而不是运行时的。另外,我不确定如何使用模板,因为某些子计算 classes 需要构造函数参数。
我已经开始为每个步骤实现虚拟 'interface' classes 并在构造函数中将每个步骤作为 unique_ptr 注入,但不确定这是否正确 'modern C++'方式。
我最初开始在主要 class 中实现所有功能,但发现这使得独立地对每个步骤进行单元测试变得困难甚至不可能。
结构类似于下面:
class CalculationStepA
{
public:
// default constructor
StepAResult performStep(const input& requiredInput);
};
class CalculationStepBType1
{
public:
// default constructor
StepBResult performStepB(const stepBInput& requiredInput);
};
class CalculationStepBType2
{
public:
CalculationStepBType2(const inputIOnlyNeedForType2& parameters)
{
// initialize class members from input
// need for this calculation type
}
StepBResult performStepB(const stepBInput& requiredInput);
};
class CalculationStepCType1
{
public:
CalculationStepBType2(const inputIOnlyNeedForType1& parameters)
{
// initialize class members from input
// need for this calculation type
}
StepCResult performStepC(const stepCInput& requiredInput);
};
class CalculationStepCType2
{
public:
CalculationStepBType2(const inputIOnlyNeedForType2& parameters)
{
// initialize class members from input
// need for this calculation type
}
StepCResult performStepB(const stepCInput& requiredInput);
};
class ClassThatUsesAllTheCalculations
{
public:
ClassThatUsesAllTheCalculations(/* take required parameters that determine which step types I need */)
{}
// possible constructor?
ClassThatUsesAllTheCalculations(
std::unique_ptr<IStepACalculationStrategy> stepA,
std::unique_ptr<IStepBCalculationStrategy> stepB,
std::unique_ptr<IStepCCalculationStrategy> stepC)
{
}
FinalResult executeCalculation(const finalInputRequiredHere& input)
{
auto stepAresult = stepACalculator(somethingFromInput);
// logic to use stepA and determine if we should continue
auto stepBresult = stepBCalculator(somethingFromStepAResult);
// again, logic to use stepB and determine if we should continue
auto stepCresult = stepCCalculator(somethingFromStepBResult);
// assemble final result
return theFinalResult
}
// other method needed to setup calculation
private:
TypeForStepACalculation stepACalculator;
TypeForStepBCalculation stepBCalculator;
TypeForStepCCalculation stepCCalculator;
};
如果能帮助确定最佳设计,我们将不胜感激。
什么是简单的继承?
struct StepA{
virtual StepAResult perform(StepAParams)=0;
};
struct someStepAImpl : public StepA{
virtual StepAResult perform(StepAParams params) override {
//actual implementation
}
};
你的计算 class 是否使用引用(必须在构造时设置)、std::reference_wrapper
(不为空,但可以稍后更改)或某种(智能)指针(可能是 nullptr
,不要忘记检查它,但在管理生命周期时最简单)取决于您计划如何使用它以及您希望如何管理对象的生命周期。像您一样使用 unique_ptr
的示例是:
class Calculator
{
public:
Calculator(
std::unique_ptr<StepA> stepA,
std::unique_ptr<StepB> stepB,
std::unique_ptr<StepC> stepC
)
:m_stepA(std::move(stepA)),m_stepB(std::move(stepB)),m_stepC(std::move(stepC))
{}
FinalResult executeCalculation(const finalInputRequiredHere& input)
{
//logic
auto stepAresult = stepA->perform(StepAParams);
//logic
auto stepBresult = stepB->perform(StepBParams);
//logic
auto stepCresult = stepC->perform(StepAParams);
//logic
return FinalResult();
}
private:
std::unique_ptr<StepA> m_stepA=nullptr;
std::unique_ptr<StepB> m_stepB=nullptr;
std::unique_ptr<StepC> m_stepC=nullptr;
};
void somewhereElse(){
std::unique_ptr<StepA> stepa(new someStepAImpl());
std::unique_ptr<StepB> stepa(new someStepBImpl());
std::unique_ptr<StepC> stepa(new someStepCImpl());
Calculator calc(
std::move(stepa),
std::move(stepb),
std::move(stepc)
);
calc.executeCalculation(...);
}