我想要完成的事情
我想利用策略模式,而策略类有类型参数。
代码是什么
假设我有以下通用抽象策略类:
abstract class Strategy[T, V]() {
def doSomething(x: Int): V
def unDoSomething(x: V): T
}
我现在推出两个具体的策略:
class StrategyOne() extends Strategy[Int, String] {
def doSomething(x: Int): String = { x.toString() }
def unDoSomething(x: String): Int = { x.toInt }
}
class StrategyTwo() extends Strategy[Double, List[Int]] {
def doSomething(x: Int): List[Int] = { List(x, 10, 20)}
def unDoSomething(x: List[Int]): Double= { x.reduceLeft(_ + _) + 0.1 }
}
现在,我们有一个使用该策略的类:
class Worker[T, V](strategy: Strategy[T, V]) {
def run() {
val res = strategy.doSomething(5) //res is a T
val res2 = strategy.unDoSomething(res) //res2 is a V
println(res2)
}
}
正如预期的那样,我现在能够实例化具有明确类型的新工作者:
val worker1 = new Worker(new StrategyOne())
val worker2 = new Worker(new StrategyTwo())
问题
但是,我也想利用某种动态策略选择,如下所示:
val strategies = Map("one" -> new StrategyOne(), "two" -> new StrategyTwo())
val worker = new Worker(strategies(args(0)))
当然,编译器告诉我,我想要的是不可能的,因为不能推断出任何类型。
问题
我知道这个星座是不幸的,但我需要T
内V
和Worker
的类型。
是否有可能使这种模式适用于这种特定情况?
答案 0 :(得分:5)
抽象类型成员应该在这里帮助你而不仅仅是输入参数。实际上,你大多想要传递Strategy
s,而不必过多关注他们的两种类型(包括将它们放在地图中)。并且在某一点(Worker
),您需要类型。
所以我建议如下(您应该在此模型中为V
和T
提供更多描述性名称,但我无法弄清楚它们的含义,因此我将它们保留原样):
abstract class Strategy {
type T
type V
def doSomething(x: Int): V
def unDoSomething(x: V): T
}
class StrategyOne extends Strategy {
type T = Int
type V = String
def doSomething(x: Int): String = {...}
def unDoSomething(x: String): Int = {...}
}
class StrategyTwo extends Strategy {
type T = Double
type V = List[Int]
def doSomething(x: Int): List[Int] = {...}
def unDoSomething(x: List[Int]): Double= {...}
}
class Worker(strategy: Strategy) {
def run(): Unit = {
val res = strategy.doSomething(5) //res is a strategy.T
val res2 = strategy.unDoSomething(res) //res2 is a strategy.V
println(res2)
}
}
在这种情况下,推断出res
和res2
的类型。但是,如果你需要写下他们的类型,它们是strategy.T
和strategy.V
,就像我在评论中写的那样(路径依赖类型,如果你想谷歌这个概念)。
您仍然可以轻松制定策略:
val worker1 = new Worker(new StrategyOne)
val worker2 = new Worker(new StrategyTwo)
现在你也可以这样做:
val strategies = Map("one" -> new StrategyOne, "two" -> new StrategyTwo)
val worker = new Worker(strategies(args(0)))
按照您的要求。而这一切都很好听。