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