Where should I inject the dependency when I write a class? Should it be given to __init__
or to the specific method that uses the dependent object?
Take the below two pieces of code for example, to me they function exactly the same way:
class TextFile:
def save_text(self, text):
print("Below texts saved to file")
print(text)
class TextWriter:
def __init__(self):
self.text = ""
def write_text(self, text):
self.text += text
def save_text(self, saver): # dependency injected in the specific method
saver.save_text(self.text)
if __name__ == "__main__":
tf_saver = TextFile()
writer = TextWriter()
writer.write_text("Here is some text")
writer.save_text(saver=tf_saver)
class TextFile:
def save_text(self, text):
print("Below texts saved to file")
print(text)
class TextWriter:
def __init__(self, saver): # dependency injected in the constructor
self.text = ""
self.saver = saver
def write_text(self, text):
self.text += text
def save_text(self):
self.saver.save_text(self.text)
if __name__ == "__main__":
tf_saver = TextFile()
writer = TextWriter(tf_saver)
writer.write_text("Here is some text")
writer.save_text()
Which design is better in this case, and why? In general, what is the rule to decide if the dependency should be given to the constructor or the specific method?
method injection
...as if we already had less of estoric terms coined for every quirk of code structure. Anyhow, in simplest terms: The dependencies that stay same for lifetime of an object should ideally be passed via constructor, while the dependencies that are local per method usage, should be provided as method parameters, together.TextWriter
class. Suppose I'm building a big system that uses aTextWriter
. You're offering two choices; Either (a) the code site that constructs theTextWriter
is responsible to decide where/how the text should be saved, or (b) the site that knows when to save must accept that responsibility. Those two sites could be far from each other in an architecture diagram, It's two different ways of thinking about whatTextWriter
does. IMO (a) feels like it should be called DI, but (b) does not.