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

时间:2014-05-25 11:51:14

标签: c++ design-patterns builder

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

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;
    }
  }
};

构建器类的一个主要缺点是成员实例的构造函数参数是重复的。 我认为这也可以通过模板实现,但我还没有找到任何资源。一个例子很好,但我想避免使用模板。任何帮助表示赞赏。我想我错过了什么......

提前致谢

1 个答案:

答案 0 :(得分:0)

在这里使用Builder模式会很危险,因为在设置所有依赖项之前,您可以调用build。 (使用构造函数注入的一个原因是阻止类实例化而不显式指定其所有依赖项。)

您应该将ComponentA注入Layer,而不是直接创建其依赖项。例如:

class Layer
{
private:
    ComponentA& componentA; // Composition
    /* ...and many other components */

public:
    Layer(ComponentA& componentA, ...) : 
        componentA(componentA), /* other components */
};

使用依赖注入时,最终应该有一个composition root来实际构建对象图。 (这是实际发生所有依赖注入的地方。)

如果您需要按需实例化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();
        ...
    }
};