一. 單例
使用 Java 來(lái)編寫(xiě)單例模式的話捐祠,可以寫(xiě)出好幾種蒙秒。同樣,使用 Kotlin 也可以寫(xiě)出多種單例模式块请。在這里介紹的是一種使用委托屬性的方式來(lái)實(shí)現(xiàn)單例的寫(xiě)法娜氏。
首先,Kotlin 在語(yǔ)法層面上支持委托模式墩新。
委托模式是軟件設(shè)計(jì)模式中的一項(xiàng)基本技巧贸弥。在委托模式中,有兩個(gè)對(duì)象參與處理同一個(gè)請(qǐng)求海渊,接受請(qǐng)求的對(duì)象將請(qǐng)求委托給另一個(gè)對(duì)象來(lái)處理绵疲。委托模式是一項(xiàng)基本技巧,許多其他的模式臣疑,如狀態(tài)模式盔憨、策略模式、訪問(wèn)者模式本質(zhì)上是在更特殊的場(chǎng)合采用了委托模式朝捆。委托模式使得我們可以用聚合來(lái)替代繼承般渡。
對(duì)于一些很常見(jiàn)的屬性,雖然我們可以在每次需要它們的時(shí)候手動(dòng)地實(shí)現(xiàn)它們芙盘,但更好的方法是一次性全部實(shí)現(xiàn),然后放進(jìn)一個(gè)庫(kù)里面脸秽。換句話說(shuō)儒老,對(duì)其屬性值的操作不再依賴于其自身的getter()/setter()方法,而是將其托付給一個(gè)代理類记餐,從而每個(gè)使用類中的該屬性可以通過(guò)代理類統(tǒng)一管理驮樊。這種方式是委托屬性
。
在Kotlin的標(biāo)準(zhǔn)庫(kù)中有一系列的標(biāo)準(zhǔn)委托,not null屬性是其中之一囚衔。它會(huì)含有一個(gè)可null的變量并會(huì)在我們?cè)O(shè)置這個(gè)屬性的時(shí)候分配一個(gè)真實(shí)的值挖腰。如果這個(gè)值在被獲取之前沒(méi)有被分配,它就會(huì)拋出一個(gè)異常练湿。
當(dāng)然 by lazy 也可以實(shí)現(xiàn)單例猴仑,下面我們使用 not null 委托來(lái)實(shí)現(xiàn) Application 的單例。
class App : Application() {
companion object {
var instance: App by Delegates.notNull()
}
override fun onCreate() {
super.onCreate()
instance = this
}
}
二. 封裝Extras
使用ExtrasDelegate來(lái)封裝Extras
import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity
import kotlin.reflect.KProperty
/**
*
* @FileName:
* com.safframework.delegate.extras.Extras.kt
* @author: Tony Shen
* @date: 2018-06-11 23:56
* @version V1.0 <描述當(dāng)前版本功能>
*/
class ExtrasDelegate<out T>(private val extraName: String, private val defaultValue: T) {
private var extra: T? = null
operator fun getValue(thisRef: AppCompatActivity, property: KProperty<*>): T {
extra = getExtra(extra, extraName, thisRef)
return extra ?: defaultValue
}
operator fun getValue(thisRef: Fragment, property: KProperty<*>): T {
extra = getExtra(extra, extraName, thisRef)
return extra ?: defaultValue
}
}
fun <T> extraDelegate(extra: String, default: T) = ExtrasDelegate(extra, default)
fun extraDelegate(extra: String) = extraDelegate(extra, null)
@Suppress("UNCHECKED_CAST")
private fun <T> getExtra(oldExtra: T?, extraName: String, thisRef: AppCompatActivity): T? =
oldExtra ?: thisRef.intent?.extras?.get(extraName) as T?
@Suppress("UNCHECKED_CAST")
private fun <T> getExtra(oldExtra: T?, extraName: String, thisRef: Fragment): T? =
oldExtra ?: thisRef.arguments?.get(extraName) as T?
封裝完之后肥哎,在MainActivity中傳遞參數(shù)跳轉(zhuǎn)到其他到Activity辽俗。
import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.safframework.delegate.R
import com.safframework.delegate.domain.User
import com.safframework.ext.click
import kotlinx.android.synthetic.main.activity_main.*
/**
*
* @FileName:
* com.safframework.delegate.activity.MainActivity.java
* @author: Tony Shen
* @date: 2018-06-13 12:03
* @version V1.0 <描述當(dāng)前版本功能>
*/
class MainActivity:AppCompatActivity() {
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initViews()
}
private fun initViews() {
text1.click{
val intent = Intent(this@MainActivity, Demo4ExtrasDelegateActivity::class.java)
val u = User("Tony","123456")
intent.putExtra("user",u)
intent.putExtra("string","just a test")
startActivity(intent)
}
text2.click {
val intent = Intent(this@MainActivity, Demo4PrefsDelegateActivity::class.java)
startActivity(intent)
}
}
}
這里的click函數(shù),在使用Kotlin高效地開(kāi)發(fā)Android App(二)中已經(jīng)講述過(guò)篡诽,就不在重復(fù)講述崖飘。
Demo4ExtrasDelegateActivity接受從MainActivity中傳遞過(guò)來(lái)的參數(shù)。
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.safframework.delegate.domain.User
import com.safframework.delegate.extras.extraDelegate
import com.safframework.log.L
/**
*
* @FileName:
* com.safframework.delegate.activity.Demo4ExtrasDelegateActivity.java
* @author: Tony Shen
* @date: 2018-06-13 17:42
* @version V1.0 <描述當(dāng)前版本功能>
*/
class Demo4ExtrasDelegateActivity: AppCompatActivity() {
private val user: User? by extraDelegate("user")
private val s:String? by extraDelegate("string")
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
L.json(user)
L.i(s)
}
}
所傳遞過(guò)來(lái)的任何對(duì)象類型杈女,都可以使用如下的方式獲取Extras朱浴。只要保證,extra的key正確即可达椰。
private val user: User? by extraDelegate("user")
private val s:String? by extraDelegate("string")
與Extra類似翰蠢,SharedPreferences也可以使用屬性委托的方式進(jìn)行封裝。
三. infix
中綴表達(dá)式是一種通用的算術(shù)或邏輯公式表示方法砰碴,操作符以中綴形式處于操作數(shù)的中間躏筏。中綴表達(dá)式允許我們使用一個(gè)單詞或字母來(lái)當(dāng)運(yùn)算符用(其本質(zhì)還是函數(shù)調(diào)用),忽略調(diào)用的點(diǎn)和圓括號(hào)呈枉。
Kotlin的中綴表達(dá)式趁尼,需要滿足以下條件:
- 使用infix修飾
- 只有一個(gè)參數(shù)
- 其參數(shù)不得接受可變數(shù)量的參數(shù)且不能有默認(rèn)值。
例如:
infix fun Int.add(i:Int):Int = this + i
infix fun Int.加(i:Int):Int = this + i
fun main(args: Array<String>) {
println(5 add 10)
println(5 加 10)
}
執(zhí)行結(jié)果:
15
15
在 Kotlin 中猖辫,使用中綴表達(dá)式最經(jīng)典的例子酥泞,莫過(guò)于使用kxdate來(lái)操作日期。
kxdate github地址:https://github.com/yole/kxdate
val twoMonthsLater = 2.months.fromNow
val yesterday = 1.days.ago
等價(jià)于:
val twoMonthsLater = 2 months fromNow
val yesterday = 1 days ago
由此可見(jiàn)啃憎,中綴表達(dá)式能讓代碼看起來(lái)更加接近于自然語(yǔ)言芝囤。
四. inline
Kotlin 天生支持函數(shù)式編程,高階函數(shù)和 lambda 是其一大特色辛萍。
使用高階函數(shù)會(huì)帶來(lái)一些運(yùn)行時(shí)間效率的損失:每一個(gè)函數(shù)都是一個(gè)對(duì)象悯姊,并且都會(huì)捕獲一個(gè)閉包。 即那些在函數(shù)體內(nèi)會(huì)被訪問(wèn)的變量贩毕。 內(nèi)存分配(對(duì)于函數(shù)對(duì)象和類)和虛擬調(diào)用會(huì)引入運(yùn)行時(shí)間開(kāi)銷悯许。
使用 inline 修飾的函數(shù),可以從編譯器角度將函數(shù)的函數(shù)體復(fù)制到調(diào)用處實(shí)現(xiàn)內(nèi)聯(lián)辉阶。
在很多情況下先壕,通過(guò)將 Lambda 表達(dá)式內(nèi)聯(lián)在使用處, 可以消除運(yùn)行時(shí)消耗瘩扼。
翻看 Kotlin 的 Standard.kt 可以發(fā)現(xiàn)它里面的函數(shù) with、apply垃僚、run集绰、let 等都使用了 inline。
再舉一個(gè)例子谆棺,對(duì) Closeable 進(jìn)行擴(kuò)展栽燕,讓它支持Java的try-with-resources
特性包券。
inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {
var closed = false
try {
return block(this)
} catch (e: Exception) {
closed = true
try {
this?.close()
} catch (closeException: Exception) {
}
throw e
} finally {
if (!closed) {
this?.close()
}
}
}
該方法已經(jīng)在 https://github.com/fengzhizi715/SAF-Kotlin-Utils 中
總結(jié)
本文是該系列最后一篇文章,未來(lái)不會(huì)整理零碎的開(kāi)發(fā)細(xì)節(jié)溅固,轉(zhuǎn)而會(huì)以體系化形式進(jìn)行整理。
該系列的相關(guān)文章:
使用Kotlin高效地開(kāi)發(fā)Android App(四)
使用Kotlin高效地開(kāi)發(fā)Android App(三)
使用Kotlin高效地開(kāi)發(fā)Android App(二)
使用Kotlin高效地開(kāi)發(fā)Android App(一)