使用 Java 来编写单例模式的话,能够写出好几种。一样,使用 Kotlin 也能够写出多种单例模式。在这里介绍的是一种使用委托属性的方式来实现单例的写法。java
首先,Kotlin 在语法层面上支持委托模式。android
委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另外一个对象来处理。委托模式是一项基本技巧,许多其余的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式。委托模式使得咱们能够用聚合来替代继承。git
对于一些很常见的属性,虽然咱们能够在每次须要它们的时候手动地实现它们,但更好的方法是一次性所有实现,而后放进一个库里面。换句话说,对其属性值的操做再也不依赖于其自身的getter()/setter()方法,而是将其托付给一个代理类,从而每一个使用类中的该属性能够经过代理类统一管理。这种方式是委托属性
。github
在Kotlin的标准库中有一系列的标准委托,not null属性是其中之一。它会含有一个可null的变量并会在咱们设置这个属性的时候分配一个真实的值。若是这个值在被获取以前没有被分配,它就会抛出一个异常。编程
固然 by lazy 也能够实现单例,下面咱们使用 not null 委托来实现 Application 的单例。json
class App : Application() {
companion object {
var instance: App by Delegates.notNull()
}
override fun onCreate() {
super.onCreate()
instance = this
}
}
复制代码
使用ExtrasDelegate来封装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 <描述当前版本功能> */
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中传递参数跳转到其余到Activity。bash
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 <描述当前版本功能> */
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函数,在使用Kotlin高效地开发Android App(二)中已经讲述过,就不在重复讲述。闭包
Demo4ExtrasDelegateActivity接受从MainActivity中传递过来的参数。app
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 <描述当前版本功能> */
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)
}
}
复制代码
所传递过来的任何对象类型,均可以使用以下的方式获取Extras。只要保证,extra的key正确便可。
private val user: User? by extraDelegate("user")
private val s:String? by extraDelegate("string")
复制代码
与Extra相似,SharedPreferences也可使用属性委托的方式进行封装。
中缀表达式是一种通用的算术或逻辑公式表示方法,操做符以中缀形式处于操做数的中间。中缀表达式容许咱们使用一个单词或字母来当运算符用(其本质仍是函数调用),忽略调用的点和圆括号。
Kotlin的中缀表达式,须要知足如下条件:
例如:
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)
}
复制代码
执行结果:
15
15
复制代码
在 Kotlin 中,使用中缀表达式最经典的例子,莫过于使用kxdate来操做日期。 kxdate github地址:https://github.com/yole/kxdate
val twoMonthsLater = 2.months.fromNow
val yesterday = 1.days.ago
复制代码
等价于:
val twoMonthsLater = 2 months fromNow
val yesterday = 1 days ago
复制代码
因而可知,中缀表达式能让代码看起来更加接近于天然语言。
Kotlin 天生支持函数式编程,高阶函数和 lambda 是其一大特点。
使用高阶函数会带来一些运行时间效率的损失:每个函数都是一个对象,而且都会捕获一个闭包。 即那些在函数体内会被访问的变量。 内存分配(对于函数对象和类)和虚拟调用会引入运行时间开销。
使用 inline 修饰的函数,能够从编译器角度***将函数的函数体复制到调用处实现内联。***
在不少状况下,经过将 Lambda 表达式内联在使用处, 能够消除运行时消耗。
翻看 Kotlin 的 Standard.kt 能够发现它里面的函数 with、apply、run、let 等都使用了 inline。
再举一个例子,对 Closeable 进行扩展,让它支持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()
}
}
}
复制代码
该方法已经在 https://github.com/fengzhizi715/SAF-Kotlin-Utils 中
本文是该系列最后一篇文章,将来不会整理零碎的开发细节,转而会以体系化形式进行整理。
该系列的相关文章:
Java与Android技术栈:每周更新推送原创技术文章,欢迎扫描下方的公众号二维码并关注,期待与您的共同成长和进步。