在初始化列表中初始化许多对象成员变量

Initializing many object member variables in initializer list

本文关键字:初始化 成员 变量 多对象 列表      更新时间:2023-10-16

我有一个关于在一个类中初始化多个对象成员的最佳实践的问题。这个问题的背景是一个嵌入式项目,我经常使用引用和构造函数注入:

class ComponentA 
{
public:
   ComponentA(SomeComponent1& dependency1, SomeComponent2& dependeny2)
private:
   /* ... */
};

现在假设我有许多其他类,如ComponentA,它们必须在一个类中实例化:

class Layer
{
private:
  ComponentA componentA; // Composition
  /* ...and many other components */
public:
  Layer(SomeComponent1& firstDepOfA, SomeComponent2& secondDepOfA, ...) : 
       componentA(firstDepOfA, secondDepOfA), /* other components */
};

我正在考虑使用构建器模式来减少复杂性:

class Layer
{
private:
  ComponentA componentA; // Composition
  /* ...and many other components */
  /* now private */
  Layer(SomeComponent1& firstDepOfA, SomeComponent2& secondDepOfA, ...) : 
       componentA(firstDepOfA, secondDepOfA), /* other components */
public:
  ComponentAIntf& getComponentA ( ... ); 
  class Builder
  {
  private:
    SomeComponent1* firstDepOfA;
    SomeComponent2* secondDepOfA;
    /* other dependencies/constructor parameters */
  public:
    /* returns Builder, because we want a fluent api */
    Builder& setFirstDepOfA(SomeComponent1* dep) {firstDepOfA = dep; return *this;}
    Builder& setSecondDepOfA(SomeComponent2* dep) {secondDepOfA = dep; return *this;}
    Layer& build()
    {
       /* check parameters */
       ... 
       /* create instance, constructor will be called once when scope is entered */
       static Layer layer(/* parameters */);
       return layer;
    }
  }
};

构造器类的主要缺点是成员实例的构造器参数是重复的。我认为这也可以实现与模板,但我还没有找到任何资源。举个例子就好了,但是我想避免使用模板。任何帮助都是感激的。我想我错过了什么……

Thanks in advance

在这里使用Builder模式是危险的,因为您可能在设置所有依赖项之前调用build。(使用构造函数注入的原因之一是防止类在没有显式指定其所有依赖项的情况下被实例化。)

你应该把ComponentA注入到Layer中,而不是让它直接产生依赖。例如:

class Layer
{
private:
    ComponentA& componentA; // Composition
    /* ...and many other components */
public:
    Layer(ComponentA& componentA, ...) : 
        componentA(componentA), /* other components */
};

当使用依赖注入时,你最终应该有一个组合根,在那里你实际构建你的对象图。(这是所有依赖注入实际发生的地方。)

如果您需要按需实例化ComponentA,那么您可以考虑将责任委托给工厂:

class ComponentFactory
{
private:
    SomeComponent1* firstDepOfA;
    SomeComponent2* secondDepOfA;
    /* other dependencies/constructor parameters */
public:
    ComponentFactory(SomeComponent1* firstDepOfA, SomeComponent2* secondDepOfA, ...) :
        firstDepOfA(firstDepOfA), secondDepOfA(secondDepOfA), ...
    {
    }
    ComponentA CreateComponentA()
    {
        return ComponentA(firstDepOfA, secondDepOfA);
    }
    ...
};
class Layer
{
private:
    ComponentFactory& componentFactory; // Composition
    /* ...and many other components */
public:
    Layer(ComponentFactory& componentFactory, ...) : 
        componentFactory(componentFactory), /* other components */
    void DoSomethingThatUsesComponentA()
    {
        ComponentA = componentFactory.CreateComponentA();
        ...
    }
};