2014-05-11 31 views
2

考虑一下我有一个接口有多个实现的情况,每个实现都在我的应用程序中正常部署中处于活动状态。举一个更具体的例子,我们可以认为这些接口的实现是PushNotifierEmailNotifierSmsNotifierScala多实现设计

在Java中,使用Spring,我将所有3注入到一个类中,并创建一个Map<NotificationType, Notifier>,我可以使用它来获取某种类型通知的通知程序。

我在想什么最好的模式是在Scala中做同样的事情。我见过的大多数事情都表明模式匹配:

notificationType match { 
    case Push => pushNotifier.notify 
    case Email => emailNotifier.notify 
    // ... 
} 

但是这似乎有点失败了DI/IoC的目的。然而,没有一个主要的Scala DI框架提供了一个很好的机制来将多个相同接口的实现注入为一个列表(实际上,我现在在Scala中使用Spring),但是试图避免大多数疯狂的功能并仅仅使用它对于基本的布线)

有没有一个更斯卡拉式的模式,因为我没有把握?

+0

也许这是因为我从来没有使用DI框架,但是我不清楚最终目标是什么。为什么你需要测试这是什么类型的通知器?为什么不把它变成黑盒子特质? – Owen

+0

@Owen我有这个特质的多个实现,每个都处理不同类型的通知。还有其他方法可以处理这个问题,但使用地图是最高效的方法(与每次迭代调用'supports'方法或类似方法相反) –

回答

1

这不是框架带(或缺乏)有关,但一个Scalish此举将注入该协会作为一个函数,而不是作为一个地图。斯卡拉地图也是一个功能。的T

鉴于枯燥的类型令牌和实例相关联:

scala> object Types extends Enumeration { val AType, BType, CType = Value } 
defined object Types 

scala> import Types._ 
import Types._ 

scala> trait T { def t: String } 
defined trait T 

scala> case class A(t: String = "a") extends T 
defined class A 

scala> case class B(t: String = "b") extends T 
defined class B 

scala> case class C(t: String = "c") extends T 
defined class C 

并配有功能使用它的应用程序:

scala> trait AnApp { val types: Value => T ; def f(t: Value) = types(t).t } 
defined trait AnApp 

然后注入其作为地图:

scala> object MyApp extends AnApp { val types = Map(AType -> A("a1"), BType -> B(), CType -> C()) } 
defined object MyApp 

scala> MyApp f BType 
res0: String = b 

或模式匹配匿名函数:

scala> object AnotherApp extends AnApp { val types: Value => T = { 
    | case AType => A("a2") case BType => B() case CType => C() } } 
defined object AnotherApp 

scala> AnotherApp f CType 
res1: String = c 

实际上它是使用def更方便:

scala> trait AnApp { def types: Types.Value => T ; def f(t: Types.Value) = types(t).t } 
defined trait AnApp 

scala> object AnyApp extends AnApp { def types = { 
    | case AType => A("a2") case BType => B() case CType => C() } } 
defined object AnyApp 

你不要用VAL拿到类型推断,但我似乎记得他们想补充一点。

0

你看过Guice吗?它也适用于scala。你可以连接符合你的用例的模块。注意下面的代码(Scala不是xml!),您可以定义哪个接口用于哪个模块。

https://github.com/codingwell/scala-guice/

这里是斯卡拉 - 吉斯的例子:你的情况,你会在CreditCardPaymentService变成一系列NotificationService年代。你会放一个“绑定”为您的每个通知类型的

class MyModule extends AbstractModule with ScalaModule { 
    def configure { 
    bind[Service].to[ServiceImpl].in[Singleton] 
    bind[CreditCardPaymentService] 
    bind[Bar[Foo]].to[FooBarImpl] 
    bind[PaymentService].to[CreditCardPaymentService] 
    } 
}