依赖注入/继承设计模式的构造函数Args太多

时间:2012-09-04 17:05:39

标签: c++ design-patterns inheritance dependency-injection

所以我决定使用工厂设计模式和依赖注入。

class ClassA
{        
    Object *a, *b, *c;
    public:
    ClassA(Object *a, Object *b, Object *c) :
    a(a), b(b), c(c) {}
};

class ClassB : public ClassA
{        
    Object *d, *e, *f;
    public:
    ClassB(Object *a, Object *b, Object *c, Object *d, Object *e, Object *f) :
    ClassA(a, b, c), d(d), e(e), f(f) {}
};

现在,问题是classB的构造函数的参数太多了。这是一个单继承层示例,但是当继承层开始变得更深,并且当每个层类需要构造更多对象时,顶层中的构造函数结束需要太多参数才能生成!

我知道我可以使用setter而不是构造函数,但还有其他方法吗?

3 个答案:

答案 0 :(得分:6)

不推荐使用Setter进行此类操作,因为它们会导致部分构造的对象非常容易出错。构造需要许多参数的对象的常见模式是使用构建器。 ClassBBuilder的职责是创建ClassB对象。您将ClassB构造函数设为私有,并且仅允许构建器使用朋友关系调用它。现在,构建器可以看起来像这样

ClassBBuilder {
  public:
    ClassBBuilder& setPhoneNumber(const string&);
    ClassBBuilder& setName(consg string&);
    ClassBBuilder& setSurname(const string&);
    ClassB* build(); 
} 

你使用建筑师喜欢这个:

ClassB* b = ClassBBuilder().setName('alice').setSurname('Smith').build();

build()方法检查是否已设置所有必需参数,并返回正确构造的对象或NULL。创建部分构造的对象是不可能的。你仍然有一个带有许多参数的构造函数,但它是私有的,只在一个地方调用。客户不会看到它。 Builder方法也很好地记录了每个参数的含义(当你看到ClassB('foo','bar')时,你需要检查构造函数以确定哪个参数是名称,哪个是姓氏。)

答案 1 :(得分:1)

这是C ++问题之一(如果这可以称为问题)。除了试图保持ctor的参数数量最小化之外,它没有解决方案。

其中一种方法是使用道具结构,如:

struct PropsA
{
    Object *a, *b, *c;
};

class ClassA
{
    ClassA(PropsA &props, ... other params);
};

这似乎很明显,但我确实使用了好几次。在许多情况下,事实证明某些参数组是相关的。在这种情况下,为它们定义一个结构是有意义的。

这种最糟糕的噩梦是薄包装类。可以直接访问基础的方法和数据字段,同时必须复制所有ctors。当有10多个ctors时,创建一个包装器开始成为一个问题。

答案 2 :(得分:1)

我认为你所描述的不是C ++中的问题 - 实际上,C ++很好地反映了你的设计所表达的依赖关系:

  1. 要构建ClassA类型的对象,您需要有三个Object个实例(abc)。
  2. 要构建ClassB类型的对象,您还需要有三个Object个实例(def)。
  3. ClassB类型的每个对象都可以被视为ClassA类型的对象。
  4. 这意味着要构造类型为ClassB的对象,您需要提供实现Object接口所需的三个ClassA对象,然后再实现另外三个ClassB对象ClassB界面。

    我相信这里的实际问题是你的设计。您可以考虑采用不同的方法来解决这个问题:

    1. 不要让ClassA继承ClassA*。可能是也可能不是一个选项,具体取决于您是否需要对任何类型的对象进行同源访问(例如,因为您有ClassB的集合,并且此集合还可以包含指向a的指针。)
    2. 寻找总是一起出现的物体。喜欢 - 也许传递给构造函数(bde和{{1}})的前两个对象代表某种对。可能是对象标识符等?在这种情况下,为此引入专用摘要(读取:类型)可能是有益的。