昨天我們討論了 Functional Programming 利用 Function as first class citizen 來拆分邏輯的應用。今天我們來談合成的技巧。
物件導向設計裡面,我們有時會提到「以合成取代繼承」的觀念。
在 Functional Programming 裡面,我們也有類似的觀念:Functional Programming 沒有繼承,所以,我們只能以合成的方式組合邏輯。
以昨天的 code 為例:
private suspend fun PipelineContext<Unit, ApplicationCall>.root(
client: HttpClient, combineStrategy: suspend (Deferred<String>, Deferred<String>, Deferred<String>) -> String
) {
val a = async { client.get<String>("http://127.0.0.1:8080/a") }
val b = async { client.get<String>("http://127.0.0.1:8080/b") }
val c = async { client.get<String>("http://127.0.0.1:8080/c") }
val result = combineStrategy(a, b, c)
client.close()
call.respondText(result, contentType = ContentType.Text.Plain)
}
我們可以發現 async { client.get<String>() }
出現了很多次。所以我們可以抽出一個函式:
private fun PipelineContext<Unit, ApplicationCall>.getLocalhostDataAsync(client: HttpClient, Url: String) =
async { client.get<String>(Url) }
private suspend fun PipelineContext<Unit, ApplicationCall>.root(
client: HttpClient, combineStrategy: suspend (Deferred<String>, Deferred<String>, Deferred<String>) -> String
) {
val a = getLocalhostDataAsync(client, "http://127.0.0.1:8080/a")
val b = getLocalhostDataAsync(client, "http://127.0.0.1:8080/b")
val c = getLocalhostDataAsync(client, "http://127.0.0.1:8080/c")
val result = combineStrategy(a, b, c)
client.close()
call.respondText(result, contentType = ContentType.Text.Plain)
}