2013-06-12 48 views
1

我想知道是否有人有任何创建类型参数化类型层次结构的经验?我相当肯定这是由于scala伪静态包装对象的结合而导致的。类型参数化类型层次结构

具体使用情况下,我心目中是一个参数化类型的id在应用程序框架,所以你可以使用的int/long/java.util.UUID/BSONId /不管你的选择。考虑作为一个粗略的例子:

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

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

是否有任何理由,这是一个引人注目的坏主意:

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] 
} 

你会再与类似配置使用层次的项目呢?任何陷阱/我应该知道的?

+1

可能是我,但我不明白你想达到的目标。 – Jatin

回答

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 Pattern: The Bakery from the Black Lagoon

+0

这是一个更好的解决方案,原因很简单,您可以完全避免“Gen”爆炸。 –