Instead (pseudo code as general advice) ...
config <-- ... A.constructor (config) { this.foo = config.foo this.bar = config.bar this.objectB = createB (config) } B.constructor (config) { this.frob = config.frob this.objectC = createC (config) } C.constructor (config) { this.frobnicate = config.frobnicate this.objectD = createC (configD) }
you should convey only what is really necessary:
config <-- ... A.constructor (foo, bar, frob, frobnicate) { this.foo = foo this.bar = bar this.objectB = createB (frob, frobnicate) } B.constructor (frob, frobnicate) { this.frob = frob this.objectC = createC (frobnicate) } C.constructor (frobnicate) { this.frobnicate = frobnicate }
You have as local a state as possible. The global state is at the root of an indefinite number of debugging horror scenarios (since I feel like you just ran into it).
As an alternative to many classes, you donβt need to know what their objects look like, they are just interested in the open interface. You can apply dependency inversion, then:
config <-- ... objectC = createC (config.frobnicate) objectB = createB (config.frob, objectC) objectA = createA (config.foo, config.bar, objectB)
Using dependency inversion means freeing your classes from having to know too much. For example, a Car does not need to know about Trailer and its composition, it just needs to know about CouplingDevice :
trailer = createTrailer (...) couplingDevice = createCouplingDevice (...) car.install (couplingDevice) couplingDevice.attach (trailer)
source share