我有一個模式來處理使用鏈接部分函數的Web服務請求(我認爲這是一個責任鏈模式鏈)。在我的例子中,假設請求有兩個參數,一個字符串Id和一個日期。有一個涉及id的驗證步驟,檢查日期的驗證步驟,以及最終使用兩者的一些業務邏輯。所以我讓他們實現像這樣:scala:我如何鏈接不同類型的部分函數
object Controller {
val OK = 200
val BAD_REQUEST = 400
type ResponseGenerator = PartialFunction[(String, DateTime), (String, Int)]
val errorIfInvalidId:ResponseGenerator = {
case (id, _) if (id == "invalid") => ("Error, Invalid ID!", BAD_REQUEST)
}
val errorIfFutureDate:ResponseGenerator = {
case (_, date) if (date.isAfter(DateTime.now)) => ("Error, date in future!", BAD_REQUEST)
}
val businessLogic:ResponseGenerator = {
case (id, date) => {
// ... do stuff
("Success!", OK)
}
}
def handleRequest(id:String, date:DateTime) = {
val chained = errorIfInvalidId orElse errorIfFutureDate orElse businessLogic
val result: (String, Int) = chained(id, date)
// make some sort of a response out of the message and status code
// e.g. in the Play framework...
Status(result._2)(result._1)
}
}
我喜歡這種模式,因爲它是非常有表現 - 你可以很容易地掌握控制方法的邏輯是隻要看一下鏈接的功能是什麼。而且,我可以輕鬆混合並匹配不同請求的不同驗證步驟。
問題是,當我嘗試擴展這種模式時,它開始崩潰。假設我的下一個控制器接受了一個我想驗證的ID,但沒有日期參數,並且可能它有一些需要驗證的第三種類型的新參數。我不想繼續擴展那個元組到(String, DateTime, Other)
並且必須通過一個虛擬的DateTime或其他。我想有部分函數接受不同類型的參數(它們仍然可以返回相同的類型)。但我無法弄清楚如何編寫它們。
對於一個具體的問題 - 假設示例性驗證方法改成這個樣子:
val errorIfInvalidId:PartialFunction[String, (String, Int)] = {
case id if (id == "invalid") => ("Error, Invalid ID!", BAD_REQUEST)
}
val errorIfInvalidDate:PartialFunction[DateTime, (String, Int)] = {
case date if (date.isAfter(DateTime.now)) => ("Error, date in future!", BAD_REQUEST)
}
,我還可以把它們連在一起?我似乎應該能夠將元組映射到它們,但我無法弄清楚如何。
謝謝諾亞。我還沒有使用scalaz,但驗證器看起來相當不錯。理解風格運作良好。我會檢查出來的! – ryryguy