2014-02-27 71 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)) 
}