I have 2 classes that independently operate on specific file formats:
class FileWriterA and
Each class has some shared methods (e.g.,
is_closed, etc.) that when used independently are of no concern. There is, however, a relationship between the two. When used together on a particular dataset, the file formats are used together to represent a collection. In other words, some application that opens the
.a file is looking for its associated
.b file, or vice versa.
If one were to want to develop this relationship in a program, they could be used in a context such as:
with FileWriterA(args) as fwa, FileWriterB(args) as fwb: # do stuff with appropriate writer
This however does not work because of imposed limits on the formats when used as a collection. For example, when used as a collection, the
.a file has a file size limit that may be much smaller than the file size limit imposed on the
.b format itself; conversely, the
.b file size limit may be reached before that of the
.a file size limit.
To allow this I wrote another class:
class FileWriterC. It has a constructor like so:
class FileWriterC: def __init__(x, y, z): self.fwa = FileWriterA(x, y) self.fwb = FileWriterB(x, z)
I've chosen composition because the collection has-a
FileWriterN for each file type. However, there are a number of articles citing that directly instantiating a sub-object inside the constructor is bad and should be avoided. I agree that injection has its merit, but in this case I believe that injection serves no purpose as the format is unlikely to change and
FileWriterC is simply a wrapper, combining operations; it does not depend on
self.fwb as it controls their life cycle. This leads to the first question:
How is composition achieved without direct instantiation (i.e. new Class())?
The only alternative I see is aggregation through injection:
fwc = FileWriterC() fwc.setFWA(FileWriterA(x, y)) fwc.setFWB(FileWriterB(x, z))
This seems incredibly verbose, although flexible for testing in the unlikely event other implementations of
FileWriterB were developed. Further, composition made sense as the lifecycle of these objects
Which ultimately leads to the opinion filled:
When would it be fine to allow direct instantiation in a constructor?