Kotlin解析之设计模式

前言

设计模式是我们Android成长之路必备的一项技能,相信很多同学都已经Get了,现在让我们来看看在Kotlin中设计模式是如何表达的呢。

单例模式

单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例 。
使用场景: 确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源。

  • Java单例模式回顾
    懒汉式:
 public class Singleton{

        private volatile static Singleton sInstance;

        private Singleton() {}

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

    }

饿汉式:

public class Singleton {

        public static Singleton getInstance() {
            return SingletonInstance.sInstance;
        }

        private static class SingletonInstance {
            private static final Singleton sInstance = new Singleton();
        }

    }
  • Kotlin单例模式写法
object Singleton {
}

kotlin写法是不是简单直接越看越喜欢,一句话就概括了。
来看一下官方的说明

Singleton may be useful in several cases, and Kotlin (after Scala) makes it easy to declare singletons, This is called an object declaration, and it always has a name following the object keyword.Object declaration's initialization is thread-safe.

在 Kotlin 当中直接通过关键字 object 声明一个单例,并且它是线程安全的,并且object 声明的方式也是延迟加载的。

代理模式(委托模式)

代理模式是为其他对象提供一种代理以控制对这个对象的访问

代理模式是使用一个代理对象来访问目标对象的行为,Kotlin 下的实现与 Java 基本类似

抽象类

abstract class Notify(var context: Context) {
    var notificationManager: NotificationManager? = null
    var builder: NotificationCompat.Builder? = null

    init {
        notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager
        builder = NotificationCompat.Builder(context)
        builder?.apply {
            setSmallIcon(R.mipmap.ic_launcher)
                    .setContentIntent(PendingIntent.getActivity(context, 0,
                            Intent(context, NotifyActivity::class.java),
                            PendingIntent.FLAG_UPDATE_CURRENT))
        }
    }

    /**
     * 发送一条通知
     */
    abstract fun send()

    /**
     * 取消一条通知
     */
    abstract fun cancel()
}

被代理类

class NotifyNormal(context: Context) : Notify(context) {
    override fun send() {
        builder?.let {
            it.setContent(RemoteViews(context.packageName, R.layout.layout_notify_normal))
            val notification = it.build()
            notificationManager?.notify(0, notification)
        }
    }

    override fun cancel() {
        notificationManager?.cancel(0)
    }

}
class NotifyBig(context: Context) : Notify(context) {

    override fun send() {
        builder?.let {
            it.setContent(RemoteViews(context.packageName, R.layout.layout_notify_normal))
            it.setCustomBigContentView(RemoteViews(context.packageName, R.layout.layout_notify_normal))
            val notification = it.build()
            notificationManager?.notify(0, notification)
        }
    }

    override fun cancel() {
        notificationManager?.cancel(0)
    }
}
class NotifyHeadersUp(context: Context) : Notify(context) {

    override fun send() {
        builder?.let {
            it.setContent(RemoteViews(context.packageName, R.layout.layout_notify_normal))
            it.setCustomBigContentView(RemoteViews(context.packageName, R.layout.layout_notify_normal))
            it.setCustomHeadsUpContentView(RemoteViews(context.packageName, R.layout.layout_notify_normal))
            val notification = it.build()
            notificationManager?.notify(0, notification)
        }
    }

    override fun cancel() {
        notificationManager?.cancel(0)
    }
}

代理类

class NotifyProxy(context: Context) : Notify(context) {

    private var notify: Notify? = null

    init {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            notify = NotifyHeadersUp(context)
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            notify = NotifyBig(context)
        } else {
            notify = NotifyNormal(context)
        }
    }

    override fun send() {
        notify?.send()
    }

    override fun cancel() {
        notify?.cancel()
    }
}

调用

NotifyProxy(this@MainActivity).send()

通过代理模式可以把复杂的判断和生成通知的逻辑都屏蔽了,让代码更加清晰

建造者模式

建造者模式是将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示

比如我们常用的 AlertDialog 、universal-image-loader就是使用的建造者模式,让我们看看kotlin中该怎么表达

class Dog private constructor(builder: Builder) {
    internal var name: String? = null

    init {
        name = builder.name
    }

    class Builder {
        internal var name: String? = null
        fun name(name1: String): Builder {
            name = name1
            return this
        }

        fun build(): Dog {
            return Dog(this)
        }
    }
}

使用方法与Java一样

Dog.Builder().name("旺财").build()

其实Kotlin 的 apply 扩展原生也支持 Builder 模式

class Cat {
    var name: String = "miaomiao"
    var age = 0
}
Cat().apply {
            name = "momo"
            age = 1
        }

观察者模式

观察者模式是定义对象间的一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新

常见的观察者模式如RecyclerView的Adapter的notifyDataSetChanged更新方法、BroadcastReceiver、开源库EventBus、RxJava等等
Kotlin的写法与Java类似

通过UnReadMessageObserver 单例来实现全局观察管理未读消息

object UnReadMessageObserver {

    private var map = mutableMapOf<String, UnReadMessageListener>()

    fun addUnReadMessageListener(listenerKey: String, listener: UnReadMessageListener) {
        map[listenerKey] = listener
    }

    fun updateUnReadMessage(count: Int) {
        map.forEach {
            it.value.updataUnReadMessage(count)
        }
    }

    fun removeUnReadMessageListener(listenerKey: String) {
        if (map.containsKey(listenerKey)) {
            map.remove(listenerKey)
        }
    }
}

interface UnReadMessageListener {
    fun updataUnReadMessage(unReadCount: Int)
}

被观察者

UnReadMessageObserver.updateUnReadMessage(1)

观察者

UnReadMessageObserver.addUnReadMessageListener(MainActivity::class.java.name, object : UnReadMessageListener {
            override fun updataUnReadMessage(unReadCount: Int) {
                Toast.makeText(this@MainActivity, "count:$unReadCount", Toast.LENGTH_SHORT).show()
            }
        })

观察者模式是我们经常使用的模式,它的一个重要作用就是解耦,将观察者个被观察者解耦

适配器模式

适配器模式把一种接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作
举个栗子:手机普通充电需要5V的电压,而生活用电电压是220V,而我们的充电器就充当了转换适配的作用,
这里的适配器也是一个道理
适配器模式中的目标接口也就是 5V电压的接口

interface VoltageFive {
    fun Voltage5(): Int
}

适配器模式中需要被适配的接口,日常220V电压

class VoltageDaily {
    fun Voltage220(): Int {
        return 220
    }
}

适配器

class VoltageAdapter(var voltageDaily: VoltageDaily) : VoltageFive {
    
    override fun Voltage5(): Int {
        return 5
    }

    fun getVoltage220(): Int {
        return voltageDaily.Voltage220()
    }

}

以上就是适配器模式在Kotlin上的简单实现了,适配器模式的原理在于把原本不兼容的接口融合在了一起,使之能更好的协作。

总结

以上几种设计模式是我们经常会用到的,Kotlin的大多设计模式基本与Java实现大致相同,灵活的使用设计模式能让我们代码更加的灵活,便于管理。本次学习就到这了,同学们下次再见。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • 他一直到中午才醒过来。房间里是寂静的。中午明亮的阳光从阳台洒进来。刚擦过的木地板是湿的。晒衣架上晾着他洗过的衬衣。...
    英语学了没阅读 279评论 0 0
  • 打卡第二轮 90天 DAY - 52 2017.4.8 不知道写什么,有点累,想睡觉,又想打卡,写点什么,感觉是纠...
    薇糖糖糖阅读 282评论 0 0
  • RPC全称为Remote Procedure Call,翻译过来为"远程过程调用"。主要应用于不同的系统之间的远程...
    零一间阅读 1,358评论 0 5
  • 学习成长&工作事业 这周成人时间管理和亲子时间管理同时开营,有点杂。过量的信息经常导致来不及爬楼,好在很快就...
    宜红阅读 171评论 0 0
  • 多年未见信一封,秋日江南烟雨重。 常盼春来不负我,痴心一片忍寒冬。
    蛮力阅读 320评论 0 8