(Scala 2.11)
您好,
概述
我正在尝试创建一个具有可扩展类型系统的库。因为我的库太大而且复杂,所以我创建了以下示例,该示例完全不同但具有相似的继承和依赖结构。
我创造了一个'食人族'图书馆。它的目的是构建属于不同部落(类型)的食人族,具有以下特性:
该库有三个特征( AnyCannibalLike , AnyNormalCannibalLike , AnyHungryCannibalLike ),所有其他特征和类都将从中继承。该库还具有用于创建不同部落的具体案例类的抽象类。 Please look at the following image to understand the inheritance structure
图书馆代码+ JungleCannibals和UrbanCannibals示例
/////////////////////////////////////////////////////////////////////////////////////
// Any cannibal traits and abstract classes
/////////////////////////////////////////////////////////////////////////////////////
trait AnyCannibalLike {
type TBasic <: AnyCannibalLike
type TNormal <: AnyCannibalLike
type THungry <: AnyCannibalLike
type TChild <: AnyCannibalLike
//name of the cannibal
protected val _name : String
def getName() = _name
//Any cannibal can play with any cannibal
def playWith(anyCannibal : AnyCannibalLike) : Unit
//Any cannibal can bring a child of the same tribe into the world.
//If the cannibal is normal then the child will be normal
//If the cannibal is hungry then the child will be hungry
def birthChild(childName : String) : TChild
protected final def completeNameOfChild(childName : String) = childName + " (child of " + getName() + ")"
}
trait AnyNormalCannibalLike[Basic <: AnyCannibalLike] extends AnyCannibalLike {
type TBasic = Basic
type TChild = TNormal
//How to do this?
//def changeTo[Basic <: AnyCannibalLike, Normal <: AnyNormalCannibalLike[Basic], Hungry <: AnyHungryCannibalLike[Basic]]() : Normal
}
trait AnyHungryCannibalLike[Basic <: AnyCannibalLike] extends AnyCannibalLike {
type TBasic = Basic
type TChild = THungry
//Any hungry cannibal can eat other cannibals of the same tribe
def eat(sameCannibal : Basic) : Unit
//How to do this?
//def changeTo[Basic <: AnyCannibalLike, Normal <: AnyNormalCannibalLike[Basic], Hungry <: AnyHungryCannibalLike[Basic]]() : Hungry
}
abstract class AnyNormalCannibalA[Basic <: AnyCannibalLike, Normal <: AnyNormalCannibalLike[Basic], Hungry <: AnyHungryCannibalLike[Basic]](name : String) extends AnyNormalCannibalLike[Basic] {
type TNormal = Normal
type THungry = Hungry
protected val _name : String = name
def playWith(anyCannibal : AnyCannibalLike) : Unit = {
println(getName() + " playing with " + anyCannibal.getName())
}
}
abstract class AnyHungryCannibalA[Basic <: AnyCannibalLike, Normal <: AnyNormalCannibalLike[Basic], Hungry <: AnyHungryCannibalLike[Basic]](name : String, eatingTool : String) extends AnyHungryCannibalLike[Basic] {
type TNormal = Normal
type THungry = Hungry
protected val _name : String = name
def playWith(anyCannibal : AnyCannibalLike) : Unit = {
println(getName() + " playing hungrily with " + anyCannibal.getName())
}
def eat(sameCannibal : Basic) : Unit = {
println(getName() + " eating " + sameCannibal.asInstanceOf[AnyCannibalLike].getName() + " using " + eatingTool)
}
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
// Jungle cannibal traits and case classes
/////////////////////////////////////////////////////////////////////////////////////
trait JungleCannibalLike extends AnyCannibalLike {
//Jungle cannibals can hunt with other jungle cannibals
def huntWith(jungleCannibal : JungleCannibalLike) : Unit = {
println(getName() + " hunting with " + jungleCannibal.getName())
}
}
trait JungleNormalCannibalLike extends AnyNormalCannibalLike[JungleCannibalLike] with JungleCannibalLike
trait JungleHungryCannibalLike extends AnyHungryCannibalLike[JungleCannibalLike] with JungleCannibalLike {
//Jungle cannibals can hunt with and then eat other jungle cannibals
def huntAndEat(jungleCannibal: JungleCannibalLike) : Unit = {
huntWith(jungleCannibal)
eat(jungleCannibal)
}
}
case class JungleNormalCannibal(name : String) extends AnyNormalCannibalA[JungleCannibalLike, JungleNormalCannibalLike, JungleHungryCannibalLike](name) with JungleNormalCannibalLike {
def birthChild(childName : String) : TChild = JungleNormalCannibal(completeNameOfChild(childName))
}
case class JungleHungryCannibal(name : String) extends AnyHungryCannibalA[JungleCannibalLike, JungleNormalCannibalLike, JungleHungryCannibalLike](name,"hands") with JungleHungryCannibalLike {
def birthChild(childName : String) : TChild = JungleHungryCannibal(completeNameOfChild(childName))
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
// Urban cannibal traits and case classes
/////////////////////////////////////////////////////////////////////////////////////
trait UrbanCannibalLike extends AnyCannibalLike {
//Urban cannibals can read with other urban cannibals
def readWith(urbanCannibal : UrbanCannibalLike) : Unit = {
println(getName() + " reading with " + urbanCannibal.getName())
}
}
trait UrbanNormalCannibalLike extends AnyNormalCannibalLike[UrbanCannibalLike] with UrbanCannibalLike
trait UrbanHungryCannibalLike extends AnyHungryCannibalLike[UrbanCannibalLike] with UrbanCannibalLike {
//Urban cannibals can read with and then eat other urban cannibals
def readAndEat(urbanCannibal: UrbanCannibalLike) : Unit = {
readWith(urbanCannibal)
eat(urbanCannibal)
}
}
case class UrbanNormalCannibal(name : String) extends AnyNormalCannibalA[UrbanCannibalLike, UrbanNormalCannibalLike, UrbanHungryCannibalLike](name) with UrbanNormalCannibalLike {
def birthChild(childName : String) : TChild = UrbanNormalCannibal(completeNameOfChild(childName))
}
case class UrbanHungryCannibal(name : String) extends AnyHungryCannibalA[UrbanCannibalLike, UrbanNormalCannibalLike, UrbanHungryCannibalLike](name,"fork") with UrbanHungryCannibalLike {
def birthChild(childName : String) : TChild = UrbanHungryCannibal(completeNameOfChild(childName))
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
// Adopting cannibal traits and case classes
/////////////////////////////////////////////////////////////////////////////////////
trait AdoptingCannibalLike extends AnyCannibalLike {
//Adopting cannibals can adopt any hungry cannibal.
//If the adopter is hungry then the returned adopted should keep its type as is.
//If the adopter is not hungry then the returned adopted is the same type but not hungry.
//how to do this?
//def adoptHungryCannibal(hungryCannibal : AnyHungryCannibalLike[_]) : hungryCannibal.type = hungryCannibal
//val ajhc = adoptHungryCannibal(JungleHungryCannibal("jhc"))
}
trait AdoptingNormalCannibalLike extends AnyNormalCannibalLike[AdoptingCannibalLike] with AdoptingCannibalLike
trait AdoptingHungryCannibalLike extends AnyHungryCannibalLike[AdoptingCannibalLike] with AdoptingCannibalLike
case class AdoptingNormalCannibal(name : String) extends AnyNormalCannibalA[AdoptingCannibalLike, AdoptingNormalCannibalLike, AdoptingHungryCannibalLike](name) with AdoptingNormalCannibalLike {
def birthChild(childName : String) : TChild = AdoptingNormalCannibal(completeNameOfChild(childName))
}
case class AdoptingHungryCannibal(name : String) extends AnyHungryCannibalA[AdoptingCannibalLike, AdoptingNormalCannibalLike, AdoptingHungryCannibalLike](name,"my kids") with AdoptingHungryCannibalLike {
def birthChild(childName : String) : TChild = AdoptingHungryCannibal(completeNameOfChild(childName))
}
/////////////////////////////////////////////////////////////////////////////////////
测试代码
val jnc = JungleNormalCannibal("jnc")
val jhc = JungleHungryCannibal("jhc")
val unc = UrbanNormalCannibal("unc")
val uhc = UrbanHungryCannibal("uhc")
val cjnc = jnc.birthChild("cjnc")
val cjhc = jhc.birthChild("cjhc")
//Must execute
jnc.playWith(jnc)
jnc.playWith(unc)
jhc.eat(jnc)
uhc.eat(unc)
jnc.huntWith(jhc)
jhc.huntWith(jnc)
cjnc.huntWith(jhc)
cjhc.huntAndEat(jnc)
//Must produce compilation errors
jnc.huntWith(unc)
jnc.eat(jnc)
cjnc.huntWith(unc)
cjnc.eat(jnc)
问题
备注
由于我是Scala的新手,我可能没有编写传统代码。如果你看到任何错误,请指出错误。