Scala - 伴随对象中的依赖注入
Scala - Dependency injection in companion objects
我来自 Java 背景并且是函数范式的新手,所以请原谅并纠正我,我闻起来像 OOP。
我有一个特征名称 PaymentHandler
trait PaymentHandler {
def handleInit(paymentInfo: PaymentInfo, paymentConfig: PaymentConfig): Either[Future[WSResponse], Exception]
def handleComplete(paymentinfo: PaymentInfo, paymentConfig: PaymentConfig, clientToken: String): Future[Map[String, String]]
}
和
@Singleton
class PayPal extends PaymentHandler{....}
@Singleton
class BrainTree extends PaymentHandler{....}
至此一切正常。但是当我想要基于付款方式的多个 PaymentGateways 时,问题就来了。
最初我写了一个像
这样的 PaymentHandlerFactory
class PaymentHandlerFactory @Inject()(
paypal:PayPal,
braintree:BrainTree) {
def get(name:String): PaymentHandler = {
name match {
case "paypal" => paypal
case "bt" => braintree
case _ => null
}
}
}
然后使用这个PaymentHandlerFactory获取guice注入的PayPal对象。但不知何故,我觉得这不是正确的做法,于是我找到了伴生对象。所以这是我当时写的代码
object PaymentHandler {
@Inject
val paypal:PayPal = null
def apply(name:String): PaymentHandler = {
name match {
case "paypal" => paypal
case _ => null
}
}
}
当然这会失败,因为它无法注入 PayPal 对象。现在我心里有两个问题。
- 为什么我们不能在 Scala 中注入伴随对象?
- 在 Scala 中实现类似工厂的正确方法是什么?
你不能注入伴随对象的原因是因为它们是对象而不是 classes。这意味着只存在一个实例,它是由 scala 本身创建的。如果要做依赖注入,那么需要依赖的东西就必须由依赖注入框架创建。因此,如果您想使用 guice,您需要使用 class 为工厂建模。
我认为您对 class PaymentHandlerFactory
所做的是务实的方式,并且可能在大多数情况下都有效。我会避免过早地使它过于笼统。
如果你想让它更简单一点,你可以使用他们的AssistedInject。
如果您遇到有关伴随对象上的 DI 的问题,请查看以下解决方法
- 使用相应的 class 和 DI
- 在此class
上创建一个伴随对象
DI 的好处是它会传播到这个伴生对象。
如果您在 class Paypal
和 class BrainTree
上有一个伴生对象,如下所示:
@Singleton
class PayPal extends PaymentHandler{....}
object PayPal extends PayPal
@Singleton
class BrainTree extends PaymentHandler{....}
object BrainTree extends BrainTree
现在,我可以在 PaymentHandler 伴随对象中使用这些对象,如下所示:
// get the correct handler from factory
class PaymentHandler extends PaymentHandlerFactory(PayPal, BrainTree){...}
object PaymentHandler extends PaymentHandler
现在在任何 class 中,我们都可以使用 PaymentHandler.get()
我来自 Java 背景并且是函数范式的新手,所以请原谅并纠正我,我闻起来像 OOP。
我有一个特征名称 PaymentHandler
trait PaymentHandler {
def handleInit(paymentInfo: PaymentInfo, paymentConfig: PaymentConfig): Either[Future[WSResponse], Exception]
def handleComplete(paymentinfo: PaymentInfo, paymentConfig: PaymentConfig, clientToken: String): Future[Map[String, String]]
}
和
@Singleton
class PayPal extends PaymentHandler{....}
@Singleton
class BrainTree extends PaymentHandler{....}
至此一切正常。但是当我想要基于付款方式的多个 PaymentGateways 时,问题就来了。 最初我写了一个像
这样的 PaymentHandlerFactoryclass PaymentHandlerFactory @Inject()(
paypal:PayPal,
braintree:BrainTree) {
def get(name:String): PaymentHandler = {
name match {
case "paypal" => paypal
case "bt" => braintree
case _ => null
}
}
}
然后使用这个PaymentHandlerFactory获取guice注入的PayPal对象。但不知何故,我觉得这不是正确的做法,于是我找到了伴生对象。所以这是我当时写的代码
object PaymentHandler {
@Inject
val paypal:PayPal = null
def apply(name:String): PaymentHandler = {
name match {
case "paypal" => paypal
case _ => null
}
}
}
当然这会失败,因为它无法注入 PayPal 对象。现在我心里有两个问题。
- 为什么我们不能在 Scala 中注入伴随对象?
- 在 Scala 中实现类似工厂的正确方法是什么?
你不能注入伴随对象的原因是因为它们是对象而不是 classes。这意味着只存在一个实例,它是由 scala 本身创建的。如果要做依赖注入,那么需要依赖的东西就必须由依赖注入框架创建。因此,如果您想使用 guice,您需要使用 class 为工厂建模。
我认为您对
class PaymentHandlerFactory
所做的是务实的方式,并且可能在大多数情况下都有效。我会避免过早地使它过于笼统。
如果你想让它更简单一点,你可以使用他们的AssistedInject。
如果您遇到有关伴随对象上的 DI 的问题,请查看以下解决方法
- 使用相应的 class 和 DI
- 在此class 上创建一个伴随对象
DI 的好处是它会传播到这个伴生对象。
如果您在 class Paypal
和 class BrainTree
上有一个伴生对象,如下所示:
@Singleton
class PayPal extends PaymentHandler{....}
object PayPal extends PayPal
@Singleton
class BrainTree extends PaymentHandler{....}
object BrainTree extends BrainTree
现在,我可以在 PaymentHandler 伴随对象中使用这些对象,如下所示:
// get the correct handler from factory
class PaymentHandler extends PaymentHandlerFactory(PayPal, BrainTree){...}
object PaymentHandler extends PaymentHandler
现在在任何 class 中,我们都可以使用 PaymentHandler.get()