2014-02-27 69 views
0

我们的应用程序在存储层顶部有一个服务层 - 服务层方法将创建一个新的数据库会话(我们在MySql上使用Slick),并通过会议作为一个隐含参数传递给存储层方法将数据库方法从服务层注入到存储层

trait Service1 { 
    def serviceLayerMethod(params) = { 
    db withSession { 
     implicit session: Session => 
     storageLayerMethod1(params) 
     storageLayerMethod2(params) 
}}} 

object DAO1 { 
    def storageLayerMethod1(params)(implicit session: Session) 
} 

object DAO2 { 
def storageLayerMethod2(params)(implicit session: Session) 
} 

我们希望能够从服务层,存储层注入不同的方法实现,比如我们有一个multiGet方法检索多个记录,并且我们希望有这种方法的不同实现,例如一个是并行执行multiGet,另一个尝试从Redis缓存中检索数据,然后将其从数据库中拉出。我可以将这些方法作为隐式参数传递,但我希望有一种方法可以用较少的样板来完成。

trait MultiGet { 
    def multiGet(params)(implicit session: Session) 
} 

object MultiGetDefault extends MultiGet 
object MultiGetParallel extends MultiGet 
object MultiGetCached extends Multiget 

trait Servic1 { 
    def serviceLayerMethod1(params) = { 
    db withSession { 
     implicit session: Session => 
     storageLayerMethod1(params)(MultiGetDefault) 
    }} 

    def serviceLayerMethod2(params) = { 
    db withSession { 
     implicit session: Session => 
     storageLayerMethod1(params)(MultiGetParallel) 
}}} 

object DAO1 { 
    def storageLayerMethod1(params)(implicit session: Session, multiGetImpl: MultiGet) { 
    multiGetImpl.multiGet(params) 
}} 

大多数的存储层方法在单一对象,所以我不能够混入不同MultiGet实现无显著重构。服务层特征通过蛋糕模式在控制器层被实例化/注入。

+0

版本也许这个答案将满足您的需求:http://stackoverflow.com/questions/21965848/scala-write - 单元的测试换对象 - 单身 - 即-延伸-A-特质类与 –

回答

0

我们要尽量延长/包装Session与实现multiGet

trait MySession extends Session { 
    private val session: Session 

    def capabilities = session.capabiliites 
    def close = session.close 
    def conn = session.conn 
    ... 

    def multiGet(tableName: String, ids: Seq[Int]) 
} 

class DefaultSession(private val session: Session) extends MySession { 
    def multiGet(tableName: String, ids: Seq[Int]) // default implementation 
} 

class ConcurrentSession(private val session: Session) extends MySession { 
    def multiGet(tableName: String, ids: Seq[Int]) // concurrent implementation 
} 

def defaultExecute[T](fun: (MySession) => T): T = db withSession { 
    _session: Session => 
    fun(new DefaultSession(_session)) 
} 

def concurrentExecute[T](fun: (MySession) => T): T = db withSession { 
    _session: Session => 
    fun(new ConcurrentSession(_session)) 
}