[Day 28] 討論 Functional Programming 的合成

昨天我們討論了 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)
}