The Factory:
object DependencyFactory extends Factory { // The following trait has become necessary to avoid name clashes // between a FactoryMaker and its contents during implicit conversion // (e.g. FactoryMaker has method 'find' so if contained type has a // 'find' too it will not trigger the implicit conversion and you'll // get error instead) trait VendorMarker[T] { this: FactoryMaker[T] => // since our fields will be visible as Vendor (to avoid name clashes), // we need a method to get back to FactoryMaker (e.g. to use its // 'doWith' method) def asFactoryMaker: FactoryMaker[T] = this } // factory method to make FactoryMakers visible as Vendors with a // marker trait private def newVendor[T : Manifest](v: T): Vendor[T] with VendorMarker[T] = new FactoryMaker[T](v) with VendorMarker[T] implicit def vendorToValue[T](vendor: Vendor[T]): T = vendor.vend val props = newVendor[AppProperties](new AppPropertiesImpl) val db = newVendor[DbAccess](Model) val roomStore = newVendor(new RoomStore) val quizFactory = newVendor(new QuizFactory) // etc }
Usage examples:
class RoomStore { // Dependency requirements expressed with imports import lib.DependencyFactory.db // now we are using db as DbAccess via the implicit conversion def updateRoom(room: Room): Room = db.merge(room) def getRoom(id: Long): Option[Room] = db.find(classOf[Room], id) } // This one has a lot of dependencies import lib.DependencyFactory.{chatFactory, currentTime, roomStore, persistentMessageStore, questionStore} class Quiz(_room: Room) extends AbstractQuiz(chatFactory.newChat(), currentTime) { // ... } class QuizFactory { def newQuiz(room: Room) = new Quiz(room) // note the asFactoryMaker.doWith usage to temporarily replace a dependency def newQuiz(room: Room, msgs: List[Message]) = lib.DependencyFactory.chatFactory.asFactoryMaker.doWith(new ChatFactory { override def newChat(msgs: List[Message], capacity: Int) = new Chat(msgs, 100) }) { new Quiz(room) } }
Quite cool feature to use!