1

我想知道是否有人有创建类型参数化类型层次结构的经验?由于 scala 对包和静态对象的伪统一,我相当肯定这是可以实现的。

我想到的具体用例是在应用程序框架上对 id 类型进行参数化,以便您可以使用您选择的int/ long/ java.util.UUID/ BSONId/whatever。考虑一个粗略的例子:

package foolib.generic

trait GenEntity[I] { def id: I }

trait GenRepository[I] { def getById(id: I): GenEntity[I] }

trait FooTaxonomy[I] {
  type Entity = GenEntity[I]
  type Repository = GenRepository[I]

  object subpackage extends generic.subpackage.SubpackageTaxonomy[I]
}

然后,您将配置层次结构以在项目中使用,例如:

package object myprj {
  object foolib extends foolib.generic.FooTaxonomy[java.util.UUID]

  // Whee!
  val someEntity = new myprj.foolib.Entity(java.util.UUID.randomUUID())
}

有什么理由认为这是一个非常糟糕的主意吗?我应该注意的任何陷阱/等?

4

1 回答 1

1

这种方法可行,但当类型参数的数量增加时,您可能会遇到问题。也许一个解决方案是使用抽象类型成员而不是类型参数。

另一种方法是使用我认为在您的情况下提供更好解决方案的蛋糕模式。你的代码的确切逻辑让我有点难以理解,所以这个重写可能并不完全代表你的意图:

package foolib.generic


//defines common types used by all modules
trait CoreModule {

    type Id // abstract type, not commited to any particular implementation

}

//module defining the EntityModule trait
trait EntityModule { this: CoreModule => //specifying core module as a dependency

    trait GenEntity {
        def id: Id
    }

    def mkEntity(id: Id): Entity //abstract way of creating an entity

}

//defines the GenRepository trait
trait RepositoryModule { this: EntityModule with CoreModule => //multiple dependencies

    trait GenRepository {
        def getById(id: Id): GenEntity
    }

    val repository: GenRepository //abstract way of obtaining a repository

}

//concrete implementation for entity
trait EntityImplModule extends EntityModule { this: CoreModule =>
    case class Entity(val id: Id) extends GenEntity

    def mkEntity(id: Id) = Entity(id)
}

//modules that provides a concrete implementation for GenRepository
trait RepositoryImplModule extends RepositoryModule { this: CoreModule with EntityModule =>

    object RepositoryImpl extends GenRepository {
        def getById(id: Id) = mkEntity(id)
    }

}

//this unifies all your modules. You can also bind any dependencies and specify any types
object Universe
    extends CoreModule
    with EntityImplModule
    with RepositoryImplModule {

    type Id = java.util.UUID

    val repository = RepositoryImpl

    def mkEntity(id: Id) = Entity(id)

}

//usage
object Main {

    import Universe._
    import java.util.UUID

    val entity = repository.getById(UUID.randomUUID())
    println(entity.id)

}

这实现了创建独立于具体类型 Id 的实现的目标,并且还提供了一种进行依赖注入的好方法。

例如,为 提供具体实现的模块GenRepository可能需要Id. 您可以很好地创建另一个绑定Id到具体类型的模块并使其RepositoryImplModule依赖于前一个模块,从而指定此具体实现GenRepository仅适用于某种类型的 id。

Cake 模式非常强大,并且有很多变化。该视频解释得很好,如果您对此解决方案感兴趣,我建议您观看:

蛋糕图案:来自黑湖的面包店

于 2013-06-12T13:13:49.017 回答