2013-06-12 4 views
1

Мне было интересно, есть ли у кого-нибудь опыт создания иерархии типа с параметризованным типом? Я вполне уверен, что это возможно в результате псевдооединения scala пакетов & статических объектов.Иерархии типа с параметризованным типом

Специфический случай использования я имею в виду, это параметризующее тип ID злоумышленником рамках приложения, так что вы можете использовать ваш выбор int/long/java.util.UUID/BSONId/что угодно. Рассмотрим в качестве приблизительного примера:

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()) 
} 

Есть ли какие-либо причины, это невероятно плохая идея? Любые подводные камни/etc, о которых я должен знать?

+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 будет работать только для определенного типа идентификаторов.

Рисунок торта очень мощный и имеет множество вариаций. Это видео объясняет это довольно хорошо, я рекомендую вам посмотреть его, если вы заинтересованы в этом решении:

Cake Pattern: The Bakery from the Black Lagoon

+0

Это намного лучшее решение по той простой причине, что вы можете полностью избежать взрыва «Gen». –

Смежные вопросы