我们的应用程序在存储层之上有一个服务层 - 服务层方法将创建一个新的数据库会话(我们在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 :(得分: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))
}