Здесь действительно нет одного правильного ответа, и я думаю, что оба полностью действительны. Внедрение конструктора больше основано на объектно-ориентированных подходах, а внедрение функций больше соответствует программированию в функциональном стиле.
Основной способ, которым я бы определил, что является более подходящим, будет основан на том, насколько жизненный цикл объекта выровнен с его ассоциацией с объектом saver
. Если экземпляру TextWriter
когда-либо потребуется использовать только один saver
, то я, вероятно, назначу его в конструкторе, если он доступен во время построения. С другой стороны, если хранитель потенциально специфичен для каждого вызова метода, для меня имеет смысл передать его в метод, а не создавать несколько объектов ни по какой другой причине.
Это все довольно просто и относительно независимо от языка. Есть еще несколько нюансов в этом роде. Во-первых, ничто не мешает вам делать и то, и другое, например:
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, saver=None):
if saver is None:
saver = self.saver
saver.save_text(self.text)
Я считаю, что приведенное выше довольно идиоматично для Python. Этот подход можно более или менее адаптировать для работы на любом объектно-ориентированном языке. Например, в Java вы можете использовать перегруженные методы для достижения аналогичного результата. В двух словах, если вы передаете saver
, он используется, если нет, используется внедренный конструктор saver
.
Как указывает candied_orange, если сайт, на котором вызывается метод сохранения, не знает о хранителях (например, о сторонней библиотеке), то использование метода внедрения метода может показаться проблематичным. Однако существуют функциональные подходы к решению этой проблемы. В пакете functools есть много полезных вспомогательных функций, и одна из них — partial . Функция partial
принимает метод и некоторые параметры и возвращает функцию-оболочку, которая неявно их применяет. Или, если вы предпочитаете, вы можете сделать что-то подобное в коде, как описано в начале принятого ответа на этот вопрос.
В результате я не думаю, что вам следует беспокоиться о том, какой из них лучше в целом, а подумать о том, как должны использоваться объекты и функции. Я бы даже сказал, что вы почти всегда должны думать о дизайне классов таким образом. Я часто обнаруживаю, что у меня получается лучший дизайн класса, если я пишу код, который будет использовать класс и его объекты до того, как я определю класс.
Прикрепляю к посту несколько видео по теме: