So I decided to use the Factory Design Pattern along with 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) {}
};
Now, the problem is that classB has too many arguments for the constructor. This is a single inheritance-layer example, but when the inheritance layers start getting deeper, and when each layer-class needs more objects to be constructed, the constructor in the top layer ends requiring too many arguments in order to be made!
I know I could use setters instead of the constructor, but is there any other way?
Setter are not recommended for such things because they result in a partially constructed object which is very error prone. A common pattern for constructing an object that requires many parameters is the use of builder. The responsibility of ClassBBuilder is to create ClassB objects. You make ClassB constructor private and allow only builder to call it using friend relationship. Now, the builder can look somehow like this
ClassBBuilder {
public:
ClassBBuilder& setPhoneNumber(const string&);
ClassBBuilder& setName(consg string&);
ClassBBuilder& setSurname(const string&);
ClassB* build();
}
And you use the builder likes this:
ClassB* b = ClassBBuilder().setName('alice').setSurname('Smith').build();
build() method checks that all required parameters were set and it either returns properly constructed object or NULL. It is impossible to create partially constructed object. You still have a constructor with many arguments, but it is private and called only in a single place. Clients won't see it. Builder methods also nicely document what each parameter means (when you see ClassB('foo', 'bar') you need to check the constructor to figure out which parameter is a name and which is a surname).
This is one of the C++ problems (if this can be called a problem). It does not have solution other than trying to keep the number of parameters of the ctor minimal.
One of the approaches is using the props struct like:
struct PropsA
{
Object *a, *b, *c;
};
class ClassA
{
ClassA(PropsA &props, ... other params);
};
This seems obvious but I did used this several times. In many cases it turns out that some group of params are related. In this case it makes sense to define a struct for them.
My worst nightmare of this sort was with the thin wrapper classes. Methods and data fields of the base can be accessed directly while all ctors has to be duplicated. When there are 10+ ctors, creating a wrapper starts to be a problem.
I think what you're describing is not a problem in C++ - in fact, C++ reflects the dependencies expressed by your design fairly well:
ClassA
, you need to have three Object
instances (a
, b
and c
).ClassB
, you also need to have three Object
instances (d
, e
and f
).ClassB
can be treated like an object of type ClassA
.This means that for constructing an object of type ClassB
you need to provide three Object
objects which are needed for the implementation of the ClassA
interface, and then another three for the implementation of the ClassB
interface.
I believe the actual issue here is your design. You could consider different approaches to resolve this:
ClassB
inherit ClassA
. May or may not be an option depending on whether you need homogenous access to objects of either type (say, because you have a collection of ClassA*
and this collection could also contain pointers to ClassB
).a
and b
or d
and e
) represent some sort of pair. Maybe an object identifier or the like? In this case, it may be beneficial to introduce a dedicated abstract (read: type) for this.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With