没有任何有用的超类型Ferrari
and Mustang
可以使用别名。你需要用这种方法把世界从里到外包裹起来。
一种可能性是添加Garage
构建作为一种方法Car
.
另一种可能性是定义一些负责生产兼容汽车和车库的“世界”:
trait World {
type CarType <: Car[CarType]
def newCar() : CarType
def newGarage(cars: Seq[CarType]) = new ConcreteGarage[CarType](cars)
}
class FerrariWorld extends World {
type CarType = Ferrari
def newCar() = new Ferrari(Benzin())
}
class FordWorld extends World {
type CarType = Mustang
def newCar() = new Mustang(Benzin())
}
def play(world: World) {
val car = world.newCar()
println(car)
val gar = world.newGarage(Seq(car))
println(gar)
}
def test(likesFord: Boolean) {
val w = if(likesFord) new FordWorld else new FerrariWorld
play(w)
}
test(true)
test(false)
你会发现这可能会让人产生幽闭恐惧症。所以这实际上取决于您的目标场景。路径依赖类型总是会导致未来的约束。考虑这个带有类型参数的相当简单的变体:
trait Fuel { def liters: Int }
trait Make { def color: String }
case class Benzin(liters: Int = 0) extends Fuel
case class Diesel(liters: Int = 0) extends Fuel
case class Ferrari(color: String) extends Make
case class Mustang(color: String) extends Make { def race() { println( "Rrrroar" )}}
case class Car[M <: Make, F <: Fuel](make: M, fuel: F) {
def refuel(f: F): Car[M, F] = copy(make, f)
}
case class Garage[M <: Make](cars: Seq[Car[M,_]] = Seq.empty) {
def add(c: Car[M,_]) = copy(cars :+ c)
def remove(c: Car[M,_]) = copy(cars.filterNot(_ == c))
def refuel[F <: Fuel](c: Car[M,F], f: F) = copy( cars.map {
case `c` => c.refuel(f)
case other => other
})
}
val g0 = Garage[Mustang]()
val m = Car(Mustang("black"), Benzin())
val f = Car(Ferrari("red"), Benzin())
val g1 = g0.add(f) // forbidden
val g1 = g0.add(m) // ok
val g2 = g1.refuel(f, Benzin(45)) // forbidden
val g2 = g1.refuel(m, Diesel(45)) // forbidden
val g2 = g1.refuel(m, Benzin(45)) // ok
g2.cars.foreach(_.make.race()) // ok
结论:不要迷失方向……