一、單例模式
1.餓漢式
類加載時就初始化,會提前占用內存。
它基于 classloader 機制避免了多線程的同步問題,不過,instance 在類裝載時就實例化
- Java
public class Singleton {
private static Singleton S = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return S;
}
}
- Kotlin
object Singleton {
}
Kotlin是如何用一行代碼實現單例的呢?我們來看看反編譯后的java代碼:
tools--Kotlin--show Kotlin Bytecode
public final class Singleton {
public static final Singleton INSTANCE;
private Singleton() {
}
static {
Singleton var0 = new Singleton();
INSTANCE = var0;
}
}
可以看到,object修飾的類實際上就是Java里的靜態單例,而靜態代碼是隨著類加載的,只會加載一次,這樣就實現了餓漢式單例
2. 懶漢式
- Java
public class Singleton{
private static Singleton S;
private Singleton(){
}
public static getInstance(){
if(S==null){
S = new Singleton();
}
return S;
}
}
- Kotlin
class Singleton private constructor() {
companion object {
val S: Singleton by lazy { Singleton() }
}
}
注:by lazy { ... }的初始化默認是線程安全的,并且能保證by lazy { ... }代碼塊中的代碼最多被調用一次,我們深入源碼看一下,lazy修飾符是如何實現懶加載和線程安全的,關鍵方法是SynchronizedLazyImpl(initializer):
private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
private var initializer: (() -> T)? = initializer
@Volatile private var _value: Any? = UNINITIALIZED_VALUE
// final field is required to enable safe publication of constructed instance
private val lock = lock ?: this
override val value: T
get() { //此處判斷_value已被初始化,則直接返回
val _v1 = _value
if (_v1 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST")
return _v1 as T
}
return synchronized(lock) {//增加線程同步鎖,防止并發訪問
val _v2 = _value
if (_v2 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST") (_v2 as T)
} else {//未初始化時,真正實現初始化的代碼
val typedValue = initializer!!()
_value = typedValue
initializer = null
typedValue
}
}
}
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
private fun writeReplace(): Any = InitializedLazyImpl(value)
}
二、建造者模式
主要解決在軟件系統中,有時候面臨著"一個復雜對象"的創建工作,其通常由各個部分的子對象用一定的算法構成;由于需求的變化,這個復雜對象的各個部分經常面臨著劇烈的變化,但是將它們組合在一起的算法卻相對穩定。下面以我們常用的Dialog舉例:
- Java
public class Dialog {
private String left;
private String right;
private String title;
static class Builder {
private String left;
private String right;
private String title;
Builder left(String left) {
this.left = left;
return this;
}
Builder right(String right){
this.right = right;
return this;
}
Builder title(String title){
this.title = title;
return this;
}
Dialog build(){
Dialog dialog = new Dialog();
dialog.left = this.left;
dialog.right = this.right;
dialog.title = this.title;
return dialog;
}
}
}
class DialogTest{
void test(){
Dialog dialog = new Dialog.Builder().left("left").right("right").title("titlle").build();
}
}
- Kotlin
class Dialog{
var left:String =""
var right:String=""
var title:String ="title"
}
class DialogTest{
@Test
fun test(){
val dialog = Dialog().apply {
left = "left"
right = "right"
title = "title"
}
}
}
關鍵方法在于apply函數,它使得代碼塊能夠在當前對象語境下,訪問其非私有屬性和函數,執行完畢后返回當前對象:
/**
* Calls the specified function [block] with `this` value as its receiver and returns `this` value.
*
* For detailed usage information see the documentation for [scope functions](https://kotlinlang.org/docs/reference/scope-functions.html#apply).
*/
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
三、觀察者模式
- Java
觀察者
public interface Observer {
void update(Object object);
}
被觀察者
public abstract class Observable {
List<Observer> observers = new ArrayList<>();
public void register(Observer observer){
this.observers.add(observer);
}
public void unRegister(Observer observer){
this.observers.remove(observer);
}
public void notifyAllObservers(Object object){
for (Observer observer : observers) {
observer.update(object);
}
}
}
- Kotlin
interface TextChangedListener {
fun onTextChanged(newText: String)
}
class TextView {
var listener: TextChangedListener? = null
var text: String by Delegates.observable("") { prop, old, new ->
listener?.onTextChanged(new)
}
}
為了弄清楚如何實現的,我們查看下Delegates.observable的源碼:
/**
* Returns a property delegate for a read/write property that calls a specified callback function when changed.
* @param initialValue the initial value of the property.
* @param onChange the callback which is called after the change of the property is made. The value of the property
* has already been changed when this callback is invoked.
*
* @sample samples.properties.Delegates.observableDelegate
*/
public inline fun <T> observable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit):
ReadWriteProperty<Any?, T> =
object : ObservableProperty<T>(initialValue) {
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = onChange(property, oldValue, newValue)
}
是不是還沒有看懂,我們只需要關注ObervableProperty這個類就行了,這里值的改變實際上代理給了ObervableProperty
/**
* Implements the core logic of a property delegate for a read/write property that calls callback functions when changed.
* @param initialValue the initial value of the property.
*/
public abstract class ObservableProperty<T>(initialValue: T) : ReadWriteProperty<Any?, T> {
private var value = initialValue
/**
* The callback which is called before a change to the property value is attempted.
* The value of the property hasn't been changed yet, when this callback is invoked.
* If the callback returns `true` the value of the property is being set to the new value,
* and if the callback returns `false` the new value is discarded and the property remains its old value.
*/
protected open fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = true
/**
* The callback which is called after the change of the property is made. The value of the property
* has already been changed when this callback is invoked.
*/
protected open fun afterChange(property: KProperty<*>, oldValue: T, newValue: T): Unit {}
public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
val oldValue = this.value
if (!beforeChange(property, oldValue, value)) {
return
}
this.value = value
afterChange(property, oldValue, value)
}
}
ReadWriteProperty是一個什么東西呢?它在代理模式中用得非常多:
public interface ReadWriteProperty<in R, T> {
/**
* Returns the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @return the property value.
*/
public operator fun getValue(thisRef: R, property: KProperty<*>): T
/**
* Sets the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @param value the value to set.
*/
public operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}
當一個值被ReadWritPropery代理時,調用或者賦值都會相應地回調getValue和setValue方法
我們繼續回ObservableProperty,到從命名就可以看出來,其是一個被觀察者,當它的值發生改變時,會回調afterChange方法,最終會傳遞給我們自定義的onChange方法中,實現值的變化監聽,這樣就實現了最簡單的觀察者模式
四、代理模式
在直接訪問對象時帶來的問題,比如說:要訪問的對象在遠程的機器上。在面向對象系統中,有些對象由于某些原因(比如對象創建開銷很大,或者某些操作需要安全控制,或者需要進程外的訪問),直接訪問會給使用者或者系統結構帶來很多麻煩,我們可以在訪問此對象時加上一個對此對象的訪問層。下面舉一個經紀人代理明星的例子:
interface People {
fun speak()
}
class Broker :People{
override fun speak() {
print("hello")
}
}
class Star(private val broker: Broker) :People by broker
class Test{
@Test
fun test(){
val broker = Broker()
val star = Star(broker)
star.speak()
}
}
在Koltin中實現代理模式非常簡單,只需要試用by關鍵字就行了,上面的Star就是通過 傳入的broker實現的代理,我們看到它自身是沒有實現People類的抽象方法的,最終在test()中調用的實際上是其代理對象broker的speak,在Kotlin中by關鍵字主要有如下幾點作用:
- 類的代理 class
- 屬性延遲加載 lazy
- 監聽屬性變化 Delegates.observable ( 擴展 Delegates.vetoable )
- 自定義監聽屬性變化 ReadWriteProperty
我們再舉個栗子,看看其如何實現屬性的代理,和上面講過的觀察者模式有些類似
class Delegate {
// 運算符重載
operator fun getValue(thisRef: Any?, prop: KProperty<*>): String {
return "$thisRef, thank you for delegating '${prop.name}' to me!"
}
operator fun setValue(thisRef: Any?, prop: KProperty<*>, value: String) {
println("$value has been assigned to ${prop.name} in $thisRef")
}
}
class Example {
var d: String by Delegate()
@Test
fun test(){
d = "d value"
println("$d")
}
}
運行結果是這樣的:
從結果看,String類型的d的取值和賦值已經交給了Delegate類去實現,想不想知道如何實現的?我們來反編譯下看看源碼吧
public final class Delegate {
@NotNull
public final String getValue(@Nullable Object thisRef, @NotNull KProperty prop) {
Intrinsics.checkParameterIsNotNull(prop, "prop");
return thisRef + ", thank you for delegating '" + prop.getName() + "' to me!";
}
public final void setValue(@Nullable Object thisRef, @NotNull KProperty prop, @NotNull String value) {
Intrinsics.checkParameterIsNotNull(prop, "prop");
Intrinsics.checkParameterIsNotNull(value, "value");
String var4 = value + " has been assigned to " + prop.getName() + " in " + thisRef;
boolean var5 = false;
System.out.println(var4);
}
}
public final class Example {
// $FF: synthetic field
static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.mutableProperty1(new MutablePropertyReference1Impl(Reflection.getOrCreateKotlinClass(Example.class), "d", "getD()Ljava/lang/String;"))};
@NotNull
private final Delegate d$delegate = new Delegate();
@NotNull
public final String getD() {
return this.d$delegate.getValue(this, $$delegatedProperties[0]);
}
public final void setD(@NotNull String var1) {
Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
this.d$delegate.setValue(this, $$delegatedProperties[0], var1);
}
@Test
public final void test() {
this.setD("d value");
String var1 = String.valueOf(this.getD());
boolean var2 = false;
System.out.println(var1);
}
}
可以看到,Example中給d取值和賦值實際上調用的是getD和setD方法,而且最終轉而被Delegate對象代理,調用的是它的getValue和setValue方法,這個其實就是代理模式中by關鍵字的作用