[英]Type inference for generic strategy pattern in Scala
我想完成什么
我想利用策略模式,而策略类具有类型参数。
代码是什么样的
假设我具有以下通用抽象策略类:
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)
}
}
如预期的那样,我现在可以实例化没有显式类型的新worker:
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)))
自然,编译器告诉我,我想要的是不可能的,因为无法推断出任何类型。
题
我知道这个星座很不幸,但是我需要在Worker
中使用T
和V
的类型。 是否有可能使这种模式适用于这种特定情况?
在这里,抽象类型成员应该比类型参数有更多帮助。 确实,您大多数时候都想绕过Strategy
而不关心它们的两种类型(包括将它们放在地图中)。 在某一点上(在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
,正如我在评论中所写的(依赖路径的类型,如果要使用Google的概念)。
您仍然可以轻松创建策略:
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)))
根据您的要求。 而且所有类型检查都会很好。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.