Kotlin 中的 设计模式

单例模式

1、饿汉模式

饿汉模式在类初始化的时候就创建了对象,所以不存在线程安全问题。

局限性:

1、如果构造方法中有耗时操作的话,会导致这个类的加载比较慢;

2、饿汉模式一开始就创建实例,但是并没有调用,会造成资源浪费;

java模式下

public class ModelJavaTest {
    private static ModelJavaTest mInstance = new ModelJavaTest();
    
    public static ModelJavaTest getInstance(){
        return mInstance;
    }
    
}

Kotlin 

class ModelKotlinTest {

    object ModelKotlinTest{

    }
}

2、双重检查锁单例(DCL)

java

class SingleJavaClass {
    private volatile static SingleJavaClass instance;

    public static SingleJavaClass getInstance() {
        if (instance == null) {
            synchronized (SingleJavaClass.class) {
                if (instance == null) {
                    instance = new SingleJavaClass();
                }
            }
        }
        return instance;
    }
}

3、静态内部类

类的静态变量被初次访问会触发 java 虚拟机对该类进行初始化,即该类的静态变量的值会变为其初始化值而不是默认值(例如,引用型变量的默认值是 null , int 的默认值是 0)。因此,静态方法 getInstance() 被调用的时候 java 虚拟机会初始化这个方法所访问的内部静态类 Hold。这使得 Hold 的静态变量 INSTANCE 被初始化,从而使得 Singleton 类的唯一实例得以创建。由于类的静态变量只会创建一次,因此 singleton 也只会有一个实例变量。

public class Singleton {

    private final static class Holder {
        final static Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}

kotlin

class SingKotlinClass {
    companion object {
        val instance: SingKotlinClass by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SingKotlinClass() }
    }
}

工厂模式

java

//水果抽象类
interface Fruit {
    void showPrice();//水果价格
}

abstract class AbsFruit implements Fruit {
    public float mPrice;
}

class Apple extends AbsFruit {


    public Apple(float price) {
        mPrice = price;
    }

    @Override
    public void showPrice() {
        System.out.println("apple price is " + mPrice);
    }
}

class Banana extends AbsFruit {

    public Banana(float price) {
        mPrice = price;
    }

    @Override
    public void showPrice() {
        System.out.println("Banana price is " + mPrice);
    }
}

class FruitFactory {
    public static Fruit getApple() {
        return new Apple(5.0f);
    }

    public static Fruit getBanana() {
        return new Banana(8.0f);
    }

    public static void main(String[] args) {
        Fruit apple = FruitFactory.getApple();
        apple.showPrice();
    }
}

kotlin

interface FruitKotlin {
    val price: Float
    fun showPrice()
}

class FruitFactoryKotlin {
    companion object {
        fun getApple() = AppleKotlin(5.0f)
        fun getBanana() = BananaKotlin(8f)
    }
}

class AppleKotlin(override val price: Float) : FruitKotlin {
    override fun showPrice() {
        println("apple price is $price")
    }
}

class BananaKotlin(override val price: Float) : FruitKotlin {
    override fun showPrice() {
        println("banana price is $price")
    }
}

builder模式

builder模式也是一种常用的设计模式,常用于复杂对象的构建,例如 Android 中的 AlertDialog.

可变参数

class Car(val color: String = "black", val factory: String = "Audi")

fun main() {
    val redCar = Car(color = "red")//只关心颜色
    val bmwCar = Car(factory = "BMW")//只关心品牌
}

apply方法

apply函数时 kotlin 标准库的函数。我们先看看使用 apply 是如何构建对象

class Car2 {
    var color = "black"
    var factory = "Audi"
}

fun t() {
    val newCar = Car2().apply {
        factory = "BMW"
        color = "red"
    }
}

看一下 apply 函数 的实现

@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

从源码中可以看出,apply 函数其实是类型 T 的扩展函数。参数是一个带接受者的 lambda 表达式,执行我传入的 block 后,会把当前实例返回。 kotlin 中,可以在任何对象上使用 apply 函数,不需要额外的支持。 apply 函数的一种使用方式就是创建一个对象实例并且按照正确的方式初始化他的一些属性。和 java 当中的 builder 模式死异曲同工的效果,但是使用起来要简洁很多。

原型模式 

扩展函数

interface Shape {
    fun draw()
}

class Circle : Shape {
    override fun draw() {
        println("draw Circle")
    }
}

fun Circle.redColor(decorator: Shape.() -> Unit) {
    println("with red color extend")
    decorator()
}

fun Shape.boldLine(decorator: Shape.() -> Unit) {
    println("with bold line extend")
    decorator()
}

fun t2() {
    Circle().run {
        boldLine {
            redColor {
                draw()
            }
        }
    }
}

采用扩展函数的方式实现装饰者模式,没有中间的装饰类,代码简洁。但是只能装饰一个方法,对于多个方法都需要装饰的情况下,可能使用委托更为适合。

类委托使用 by 关键字

使用 by 关键字可以将一个接口的实现委托到实现了同样接口的另外一个对象,没有任何样板代码的产生,下面是用委托的方式实现装饰者模式。

interface Shape {
    fun draw()
    fun prepare()
    fun release()
}

class Circle : Shape {
    override fun draw() {
        println("draw Circle")
    }

    override fun prepare() {
        println("prepare Circle")
    }

    override fun release() {
        println("release Circle")
    }
}

class RedShapeKotlin(val shape: Shape) : Shape by shape {
    override fun draw() {
        println("with red color by")
        shape.draw()
    }
}

class BoldShapeKotlin(val shape: Shape) : Shape by shape {
    override fun draw() {
        println("with bold line by")
        shape.draw()
    }
}

fun test() {
    val circle = Circle()
    val decoratorShape = BoldShapeKotlin(RedShapeKotlin(shape = circle))
    decoratorShape.draw()
}

输出: 

with bold line by
with red color by
draw Circle 

小结:

Kotlin 将委托做为了语言级别的功能做了头等支持,委托是替代继承的一个很好的方法,如果多个地方需要用到相同的代码,这个是就可以考虑使用委托。

策略模式 

策略模式通常是把一系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。简单理解,策略模式就是对一个算法的不同实现。kotlin 中可以使用高阶函数替代不同算法。我么看下代码实现。

fun fullDisCount(money: Int): Int {
    return if (money > 200)
        money - 100
    else
        money
}

fun newDisCount(money: Int): Int {
    return money / 2
}

class Customer(val discount: ((Int) -> Int)) {
    fun caculate(money: Int): Int {
        return discount(money)
    }
}

fun test2() {
    val newCustomer = Customer(::newDisCount)
    val value = newCustomer.caculate(1000)

    val fullDiscountCustomer = Customer(::fullDisCount)
    val value2 = fullDiscountCustomer.caculate(300)

    println("value : $value value2: $value2")
}

输出:

value : 500 value2: 200

 模版方法

模板方法知道思想,定义一个算法中的操作框架,而将一些步骤延迟到子类中,使得子类在不改变算法框架结构即可重新定义该算法的某些特定步骤。这个模式与上面的策略模式有类似的效果。都是把不同算法实现延迟到子类中实现。与策略模式不同的是,模板行为算法有更清晰的大纲结构。完全相同的步骤会在抽象类中实现。个性化实现会在子类中实现。下面的例子展示了在线购物通过模板方法的模式支持不同的支付方式。这里和上面的策略模式类似,减少了子类的创建。

class OnLineShopping {
    fun submitOrder(pay: () -> Unit) {
        accumulatePrice()
        pay()
        sendHome()
    }

    private fun sendHome() {
        println("send home!")
    }

    private fun accumulatePrice() {
        println("accumulate price!")
    }

    fun weChatPay() {
        println("pay by weChat")
    }

    fun aliPay() {
        println("pay by aliPay")
    }


}

fun test3() {
    var shopping = OnLineShopping()
    shopping.submitOrder { shopping.weChatPay() }
    shopping.submitOrder { shopping.aliPay() }
}

输出:

accumulate price!
pay by weChat
send home!


accumulate price!
pay by aliPay
send home!

小结:

策略模式和模版方法模式都是通过高阶函数的替代继承的方式,减少了子类的创建。极大的精简了我们的代码结构。这也是我们在学习 kotlin 的时候,需要注意的地方。函数是 kotlin 中的一等公民,函数本身也具有自己的类型。函数类型和数据类型一样,即可用于定义变量,也可用作函数的形参类型,还可作为函数的返回值类型。

观察者模式 

观察者模式是应用较多的一种设计模式,尤其在响应式编程中。

一些知名框架 EventBus,RxJava等,都是基于观察者模式。 Android jetpack 中的LiveData 也是采用的观察者模式,可见这种模式应用的很广泛,看一下这个例子,用户订阅了某些视频号后,这个视频号一旦有更新,需要通知所有的订阅者用户。

interface VideoUpdateListener {
    fun update(message: String)
}

class VideoObservableInKotlin {
    var observers: MutableList<UserInKotlin> = ArrayList()
    var vid: Int by Delegates.observable(0) { _, old, new ->
        observers.forEach {
            //it.update("${it.name}_$vid")
            if (old == new) it.update("no new value")
            else it.update("${it.name}_$vid")
        }
    }
}

class UserInKotlin(val name: String) : VideoUpdateListener {
    override fun update(message: String) {
        println(message)
    }
}

fun test4() {
    val videoUpdates = VideoObservableInKotlin()
    videoUpdates.observers.add(UserInKotlin("Allen"))
    videoUpdates.observers.add(UserInKotlin("Bob"))
    videoUpdates.vid = 101
    videoUpdates.vid = 102
}

输出:

Allen_101
Bob_101
Allen_102
Bob_102

分析上面的代码,主要也是通过委托属性的方式实现了对属性值改变的监听。这里用到了一个 kotlin 标准函数 Delegates.observable 该函数有两个参数,接受一个初始值,和一个属性改变后的回调函数,回调函数有三个参数,第一个是被赋值的属性,第二个是旧值,第三个是 新值开发者可以根据自己的需求,实现属性改变后的逻辑。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值