Ну, просто потому, что мы можем открыть классы в Ruby, не значит, что мы всегда должны это делать, вы можете думать о том, чтобы открыть классы как метод последней инстанции.У вас есть библиотека, которая делает все, что вам нужно, за исключением одного метода, вместо того, чтобы разветвлять всю библиотеку, исправляя ее и используя свой форк, вы можете просто снова открыть класс, переопределить метод, и вы снова в бизнесе.Это не то, что вы бы делали волей-неволей, но способность делать это чрезвычайно полезна.
Сказав все это, в Ruby у нас есть концепция, которая почти всегда может быть хорошей заменой зависимостиинъекция - утка печатать.Поскольку нет проверки типов, вы можете передать любой объект в функцию, и пока у объекта есть методы, которые ожидала бы эта функция, все будет работать нормально.
Давайте посмотрим на ваш пример - это на самом деле не класс, способствующий внедрению зависимостей, вы не написали бы его так, например, в Java, например, если вы хотите внедрить некоторые зависимости.Вы можете вводить только через конструктор или через геттеры и сеттеры.Итак, давайте перепишем этот класс следующим образом:
class Foo
def initialize(logger)
@logger = logger
end
end
Намного лучше, что мы теперь можем внедрить / передать регистратор в наш класс Foo.Давайте добавим метод, который будет использовать этот регистратор для демонстрации:
class Foo
def initialize(logger)
@logger = logger
end
def do_stuff
@logger.info("Stuff")
end
end
В Java, если вы хотите создать Foo
объекты с различными типами регистраторов, все эти регистраторы должны будут реализовать один и тот же интерфейс в оченьбуквальный смысл (например, public class logger implements Loggable
) или, по крайней мере, дочерние классы.Но в Ruby, если у объекта есть метод info
, который принимает строку, вы можете передать ее в конструктор, и Ruby продолжает весело пыхтеть.Давайте продемонстрируем:
class Logger
def info(some_info)
end
end
class Widget
def info(some_widget_info)
end
end
class Lolcat
def info(lol_string)
end
end
Foo.new(Logger.new).do_stuff
Foo.new(Widget.new).do_stuff
Foo.new(Lolcat.new).do_stuff
Со всеми тремя из приведенных выше экземпляров класса Foo
, вызывающего метод do_stuff
, все будет работать нормально.
Как видно из этого примерасоблюдение принципов ОО-дизайна по-прежнему важно, но Ruby несколько менее ограничен в отношении того, что он примет, при условии наличия правильных методов все будет хорошо.
В зависимости от того, как вы на это смотрите, типирование утки либо делает внедрение зависимостей совершенно неуместным, либо делает его более мощным, чем когда-либо.