為可讀性設計(Design for readability)
可讀性是一種半玄學的話題,它的評價標準常常取決于上下文環(huán)境和你對一門語言的了解程度横朋。來看一個具體的例子:
// Implementation A
if (person != null && person.isAdult) {
view.showPerson(person)
} else {
view.showError()
}
// Implementation B
person?.takeIf { it.isAdult }
?.let(view::showPerson)
?: view.showError()
以上兩種實現(xiàn)在表意上是完全等價的仑乌,那么你覺得哪種可讀性更好呢?顯然琴锭,不是代碼越短可讀性就越好晰甚,代碼越簡潔,往往需要我們載入更多的關于這門語言的“方言”决帖,這些方言在特定實現(xiàn)下是提升了可讀性還是降低了可讀性厕九,這是個玄學問題。僅就上述兩種實現(xiàn)而言地回,作者和我都認為第一種可讀性更高扁远,第二種可讀性差一下,但是更加“地道”(?. takeIf let ?:)刻像。
命令式編程(A實現(xiàn))是人們的直覺畅买,也是所有編程語言的基礎結構,國際通用語言细睡;面向表達式編程(B實現(xiàn))是特定編程語言的方言谷羞,更偏向于表述做什么而不是怎么做。兩種編程方式都有其應用場景溜徙,合理使用都能提升代碼的可讀性湃缎。
現(xiàn)在假設需求變了犀填,我們需要修改代碼:
// Implementation A
if (person != null && person.isAdult) {
view.showPerson(person)
view.hideProgressWithSuccess()
} else {
view.showError()
view.hideProgress()
}
// Implementation B
person?.takeIf { it.isAdult }
?.let {
view.showPerson(it)
view.hideProgressWithSuccess()
} ?: run {
view.showError()
view.hideProgress()
}
顯然A實現(xiàn)更加便于修改,并且表意也更加清晰嗓违。B實現(xiàn)不僅不便于修改九巡,而且在此情形下,表意上與A實現(xiàn)也有細微差別(person == null情況下)靠瞎。
以上例子僅僅是為了說明比庄,在“這種情況”下,命令式編程可讀性更強乏盐,并不是說命令式編程在任何情況下都優(yōu)于表達式編程佳窑,表達式編程的主要應用場景在于各種“流”的操作上:
students
.filter { it.pointsInSemester > 15 && it.result >= 50 }
.sortedWith(compareBy({ it.surname }, { it.name }))
.joinToString(separator = "\n") {
"${it.name} ${it.surname}, ${it.result}"
}
.let(::print)
var obj = FileInputStream("/file.gz")
.let(::BufferedInputStream)
.let(::ZipInputStream)
.let(::ObjectInputStream)
.readObject() as SomeObject
典型的“流”就如上述例子給出的那樣:集合和各種Stream(肯定還有更多其它類型的流帜平,我暫時也想不起來)腰涧。Kotlin標準庫定義在集合上的擴展函數(shù)的數(shù)量我就不必贅述了,它們都為面向表達式編程提供了非常好的條件竿报;而各種Stream的層層包裝自然也是面向表達式編程很好的應用場景何吝。
流與表達式的結合可以大大提升代碼的可讀性溉委,流本身的步驟性與表達式簡潔性的結合相得益彰。這種結合可能不利于debug爱榕,不利于Kotlin初學者瓣喊,但是平衡了所得與所失之后,仍然推薦上述編程方式黔酥。