gpt4 book ai didi

scala - `trait` 的依赖注入(inject)

转载 作者:行者123 更新时间:2023-12-04 10:52:39 27 4
gpt4 key购买 nike

给定以下 FooService:

scala> trait FooService { 
| def go: Int
| }
defined trait FooService

还有一个MainService,代表一个main方法。

scala> trait MainService extends FooService { 
| def f = go + 42
| }
defined trait MainService

FooService 可以有一个假的(用于测试)和一个真实的实现(例如,命中 DB):

scala> object FakeService extends FooService { 
| def go = 10
| }
defined object FakeService

scala> object RealService extends FooService {
| def go = 55 // in reality, let's say it hit the DB and got a value
| }
defined object RealService

在我看来,添加一个“runner”类/特征,即运行 sbt run 会导致该类的执行,是可行的。它看起来像:

scala> class Main extends MainService {
| override def go = RealService.go
| }
defined class Main

我也可以定义一个测试:

scala> class Test extends MainService {
| override def go = FakeService.go
| }
defined class Test

我不太确定这是定义真实与测试 MainService 的惯用方式。请告诉我。

最佳答案

您可以使用流行的蛋糕模式,它也被称为进行依赖注入(inject)的“Scala 方式”。

乔恩做得很好 blog post关于这一点的演练(他还列出了一些替代方案)。

首先,FooService 的特性:

trait FooServiceComponent {
val fooService: FooService

trait FooService {
def go: Int
}
}

也就是说,我们需要两件事:1. 实际对象,以及 2. 它的定义/实现。两者一起命名空间。好的。以下是 FakeReal 版本:

trait FakeService extends FooServiceComponent {
class FakeService extends FooService {
def go = 10
}
}

trait RealService extends FooServiceComponent {
class RealService extends FooService {
def go = 55
}
}

现在,对于 MainService:

trait MainServiceComponent { this: FooServiceComponent =>
val mainService: MainService

class MainService extends FooService {
def f = go + 42
def go = fooService.go // using fooService
}
}

请注意自键入 this: FooServiceComponent,这是一种 Scala 方式,表示 MainServiceComponent 依赖于 FooServiceComponent。如果您尝试在不混合任何 FooServiceComponent 的情况下实例化 MainServiceComponent,那么您将遇到编译时错误。好的。 :)

现在,让我们创建具有不同特征的 TestMain 对象:

object Test extends MainServiceComponent with FakeService {
val mainService = new MainService()
val fooService = new FakeService()
}

object Main extends MainServiceComponent with RealService {
val mainService = new MainService()
val fooService = new RealService()
}

请注意,由于命名空间的原因,FakeService 无法在 Main 中访问,因为它没有混入。很好。 :) 另请注意,您将类的任何实例化延迟到此时,这很方便,因为您可以轻松地使用注册表或模拟库在一个地方替换它们。

结果:

println(Test.mainService.f) // -> 52
println(Main.mainService.f) // -> 97

希望对您有所帮助。

关于scala - `trait` 的依赖注入(inject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31215914/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com