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

Too Many Constructor Args for Dependency Injection/Inheritance Design Pattern

本文关键字:构造函数 参数 太多 设计模式 注入 继承 依赖      更新时间:2023-10-16

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

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

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

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

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('o','bar')时,你需要检查构造函数,找出哪个参数是名称,哪个是姓氏)。

这是C++问题之一(如果这可以称为问题的话)。除了尽量减少ctor的参数数量之外,它没有其他解决方案。

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

struct PropsA
{
    Object *a, *b, *c;
};
class ClassA
{
    ClassA(PropsA &props, ... other params);
};

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

我最可怕的噩梦就是使用瘦包装器类。可以直接访问基的方法和数据字段,同时必须复制所有actor。当有10个以上的因素时,创建一个包装器开始成为一个问题。

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

  1. 要构造ClassA类型的对象,需要有三个Object实例(abc
  2. 要构造ClassB类型的对象,还需要有三个Object实例(def
  3. 每一个类型为CCD_ 11的对象都可以被当作一个类型CCD_

这意味着,对于构造类型为ClassB的对象,您需要提供实现ClassA接口所需的三个Object对象,然后提供另外三个用于实现ClassB接口。

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

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