我正在尝试为通用特征的实现构建工厂。
鉴于我的域名模式:
trait Person
case class Man(firstName: String, lastName: String) extends Person
case class Woman(firstName: String, lastName: String) extends Person
我为这些类创建了一个存储库:
trait Repository[T <: Person] {
def findAll(): List[T]
}
class ManRepository extends Repository[Man] {
override def findAll(): List[Man] = {
List(
Man("Oliver", "Smith"),
Man("Jack", "Russel")
)
}
}
class WomanRepository extends Repository[Woman] {
override def findAll(): List[Woman] = {
List(
Woman("Scarlet", "Johnson"),
Woman("Olivia", "Calme")
)
}
}
到目前为止,这么好,一些非常简单的课程。但是我想根据一些参数创建一个工厂来创建这些存储库的实例。
object RepositoryFactory {
def create[T <: Person](gender: String): Repository[T] = {
gender match {
case "man" => new ManRepository()
case "woman" => new WomanRepository()
}
}
}
但这最后一部分不会编译。如果我省略工厂的显式返回类型,它会编译但返回类型为Repository[_1]
的存储库而不是Repository[Man]
我似乎无法找到合适的解决方案,你们中的任何人都有一些技巧吗?
答案 0 :(得分:1)
这个怎么样?
代码:
object GenderStuff {
trait Person
case class Man(firstName: String, lastName: String) extends Person
case class Woman(firstName: String, lastName: String) extends Person
// Note that Repository has to be covariant in P.
// See http://blogs.atlassian.com/2013/01/covariance-and-contravariance-in-scala/ for explanation of covariance.
trait Repository[+P <: Person] {
def findAll(): List[P]
}
class ManRepository extends Repository[Man] {
override def findAll(): List[Man] = {
List(
Man("Oliver", "Smith"),
Man("Jack", "Russel")
)
}
}
class WomanRepository extends Repository[Woman] {
override def findAll(): List[Woman] = {
List(
Woman("Scarlet", "Johnson"),
Woman("Olivia", "Calme")
)
}
}
sealed trait Gender {
type P <: Person
def repo: Repository[P]
}
case object Male extends Gender {
type P = Man
def repo = new ManRepository()
}
case object Female extends Gender {
type P = Woman
def repo = new WomanRepository()
}
object RepositoryFactory {
def create(gender: Gender): Repository[gender.P] = gender.repo
// or if you prefer you can write it like this
//def create[G <: Gender](gender: G): Repository[G#P] = gender.repo
}
val manRepo: Repository[Man] = RepositoryFactory.create(Male)
val womanRepo: Repository[Woman] = RepositoryFactory.create(Female)
}
当然,这使得工厂对象毫无意义 - 直接调用Male.repo
更容易:)
答案 1 :(得分:0)
你应该考虑一下你正在努力实现的目标。在您的示例中,您希望RepositoryFactory.create[Man]("woman")
返回哪种类型?编译器无法将这些任意字符串与类型相关联。