若是我想定義單例模式,那麼它應該是這樣的:java
單例是一種軟件設計模式,它保證一個類只有一個實例,而且該類提供對該實例的全局訪問控制。git
在 Java
中,一般這樣寫:github
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
複製代碼
可是上面的代碼在多線程場景下是有缺陷的。若是兩個線程同時獲取實例,則可能會建立兩個實例。因此對於上面的代碼咱們須要改造。設計模式
class Singleton {
private static Singleton instance = null;
private Singleton() {
}
private synchronized static void createInstance() {
if (instance == null) {
instance = new Singleton();
}
}
public static Singleton getInstance() {
if (instance == null) createInstance();
return instance;
}
}
複製代碼
經過 synchronized
關鍵字能夠確保在建立 instance
時沒有線程衝突,只建立一個實例。安全
在 Kotlin
中能夠這樣實現:多線程
class Singleton private constructor() {
private object HOLDER {
val INSTANCE = Singleton()
}
companion object {
val instance: Singleton by lazy { HOLDER.INSTANCE }
}
}
複製代碼
在上面的例子中,能夠看到經過 by lazy{}
確保只在第一次獲取實例時觸發,即 lazy
和 synchronized
關鍵字的效果同樣。ide
固然對於單例模式,Kotlin
提供了 object
的實現方式。函數
object Singleton
複製代碼
僅僅一行代碼就能夠實現單例模式。post
object DataProviderManager {
fun registerDataProvider(provider: DataProvider) {
// ...
}
val allDataProviders: Collection<DataProvider>
get() = // ...
}
複製代碼
就像聲明變量同樣,可是 object
的聲明不是表達式,不能進行賦值。object
聲明是線程安全的。spa
要使用 object
聲明的對象,能夠直接調用。
DataProviderManager.registerDataProvider(...)
複製代碼
一樣,object
聲明的類能夠具備父類。
object DefaultListener : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) { ... }
override fun mouseEntered(e: MouseEvent) { ... }
}
複製代碼
Kotlin
經過 object
關鍵字實現單例;object
類能夠包含屬性、函數以及 init
塊;object
是線程安全的。