【问题标题】:Arrow KT: Reader Monad vs @extension for Dependency InjectionArrow KT:Reader Monad 与 @extension 的依赖注入
【发布时间】:2020-06-07 03:09:43
【问题描述】:

我从Jorge Castillo 本人的article 中读到了关于Reader Monad 的信息,我也从Paco 那里得到了这个article。似乎两者都以不同的方式解决了Dependency Injection 的想法。 (还是我错了?)

我真的很困惑我是否理解整个Reader Monad 以及它与Paco 所谈论的Simple Depenency Injection 之间的关系。

谁能帮我理解这两件事?我会根据情况在一个项目中同时需要它们吗?

【问题讨论】:

    标签: dependency-injection reader-monad arrow-kt


    【解决方案1】:

    您的疑问是可以理解的,因为是的,这两种方法都有相同的结果:在调用堆栈中一直为您隐式传递依赖关系,因此您不需要在每个级别都显式传递它们。使用这两种方法,您都会从外部边缘传递一次依赖项,仅此而已。

    假设您有函数 a()、b()、c() 和 d(),假设每个函数调用下一个函数:a() -> b() -> c() -> d()。这就是我们的计划。

    如果您没有使用任何上述机制,并且您需要 d() 中的一些依赖项,那么您最终会在每个级别上一直转发您的依赖项(我们称之为 ctx):

    a(ctx) -> b(ctx) -> c(ctx) -> d(ctx)
    

    在使用上述两种方法中的任何一种后,它会是这样的:

    a(ctx) -> b() -> c() -> d()
    

    但是,记住这一点很重要,您可以在每个函数的范围内访问您的依赖项。这是可能的,因为使用所描述的方法,您可以启用一个封闭的上下文,该上下文会在每个级别上自动转发它们,并且每个函数都在其中运行。因此,在该上下文中,该函数可以获得这些依赖项的可见性。

    读者:这是一种数据类型。我鼓励您阅读并尝试理解这个解释数据类型的词汇表,因为这两种方法之间的区别需要了解什么是类型类和数据类型,以及它们如何协同工作:

    https://arrow-kt.io/docs/patterns/glossary/

    总而言之,数据类型代表程序数据的上下文。在这种情况下,Reader 代表需要一些依赖项才能运行的计算。 IE。像 (D) -> A 这样的计算。感谢它的 flatMap / map / 和它的其他函数以及它们的编码方式,D 将在每个级别上隐式传递,并且由于您将每个程序函数定义为Reader,您将始终在 Reader 上下文中进行操作,因此可以访问所需的依赖项 (ctx)。即:

    a(): Reader<D, A>
    b(): Reader<D, A>
    c(): Reader<D, A>
    d(): Reader<D, A>
    

    因此,将它们与 Reader 可用的组合器(如 flatMap 或 map)链接起来,您将得到 D 一直隐式向下传递并为每个级别启用(可访问)。

    另一方面,Paco 的帖子中描述的方法看起来不同,但最终实现了相同的效果。这种方法是关于利用 Kotlin 扩展函数,因为通过定义一个程序来处理所有级别的接收器类型(我们称之为上下文)将意味着每个级别都可以访问所提到的上下文及其属性。即:

    Context.a()
    Context.b()
    Context.c()
    Context.d()
    

    请注意,扩展函数接收器是一个参数,如果没有扩展函数支持,您需要在每次调用时手动作为附加函数参数传递,因此这种方式是函数所需的依赖项或“上下文”跑步。通过这种方式理解这些并理解 Kotlin 如何解释扩展函数,接收器将不需要在每个级别上手动转发,而只需传递到入口边缘:

    ctx.a() -> b() -> c() -> d()
    

    B、c 和 d 将被隐式调用,而无需您通过接收器显式调用每个级别函数,因为每个函数已经在该上下文中运行,因此它可以访问其属性(依赖项)自动启用。

    因此,一旦我们了解了两者,我们就需要选择一种,或任何其他 DI 方法。这是相当主观的,因为在函数世界中还有其他注入依赖项的替代方法,例如依赖类型类及其编译时间分辨率的无标记最终方法,或者在 Arrow 中仍然不可用但很快就会出现的 EnvIO(或等效替代)。但我不想在这里让你更加困惑。在我看来,Reader 与 IO 等其他常见数据类型结合起来有点“嘈杂”,我通常瞄准无标记的最终方法,因为这些方法允许保持由注入的类型类确定的程序约束并完全依赖 IO 运行时你的程序。

    希望这对您有所帮助,否则请随时再次提问,我们会回来回答?

    【讨论】:

    • 哇!太感谢了!现在我很好奇你提到的其他方法。我可能也会阅读这些方法。
    • 顺便说一句,还要感谢整个 47Degress 团队为您提供的所有资源。太棒了!期待更多这样的人,因为老实说,学习所有这些概念的学习曲线非常陡峭(至少对我而言)。视频格式也很棒,希望团队推出更多这样的视频。 :) 非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2015-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多