Scala: внедрение зависимостей через Reader и совместимость - PullRequest
3 голосов
/ 03 апреля 2019

Когда мы реализуем DI через Reader, мы делаем зависимость частью сигнатуры нашего метода. Предположим, что мы имеем (без реализаций):

trait Service1 { def f1:Int = ??? }
trait Service2 { def f2:Reader[Service1, Int] = ??? }

type Env= (Service1, Service2)
def c:Reader[Env, Int] = ???  //use Service2.f2 here

Теперь, f2 требуется дополнительная служба для реализации, скажем:

trait Service3
type Service2Env = (Service1, Service3)
//new dependecies on both:
trait Service2 { def f2:Reader[Service2Env, Int] = ??? }

Это сломает существующих клиентов, они больше не могут использовать Service2.f2, не предоставив Service3 дополнительно.

С DI через внедрение (через конструктор или сеттеры), что является обычным явлением в ООП, я бы использовал в качестве зависимости только c Service2. Как оно построено и каков его список зависимостей, мне все равно. С этого момента любые новые зависимости в Service2 сохранят сигнатуру функции c без изменений.

Как это решается с помощью FP? Есть варианты? Есть ли способ внедрить новые зависимости, но как-то защитить клиентов от изменений?

1 Ответ

3 голосов
/ 03 апреля 2019

Есть ли способ внедрить новые зависимости, но как-то защитить клиентов от изменений?

Это было бы своего рода побеждать цель, так как использование Reader (или, альтернативно, Final Tagless или ZIO Environment) - это способ явно объявить (прямые и косвенные) зависимости в сигнатуре типа каждой функции. Вы делаете это, чтобы иметь возможность отслеживать, где в вашем коде используются эти зависимости - просто взглянув на сигнатуру функции, вы можете сказать, может ли этот код иметь драматический побочный эффект, такой как, скажем, отправка электронного письма (или, возможно, Вы делаете это по другим причинам, но результат тот же).

Возможно, вы захотите смешать и сопоставить это с инжектором-конструктором для зависимостей / эффектов, которым не требуется этот уровень статической проверки.

...