Kotlin特色风格实现gof设计模式

虽然设计模式偏重于思想层面,但是不同的编程语言有着其独特的语法展现,这使得在某个特定语言内,可能会更灵活和更有张力的实现某些设计模式。同时,对于kotlin来说,由于其完全兼容Java,若是只是谈设计模式的实现的话,完全可以把java实现的设计模式convert成kotlin就可以了,但是这样的话,便会埋没一些kotlin的特色。

Kotlin对比java而言,其大大扩大了函数的灵活性:高阶函数(可以接受函数作为参数),扩展函数(在一个类的外面,为其声明新的方法,静态编译,实例调用)以及独立函数(不依赖于类/对象,可以独立存在于文件中)等等,这使得其实现设计模式有其独特的风格和张力,因此,本文的目的,不仅仅是简单的用kotlin实现设计模式,而是专注于发现kotlin语言的特色风格和张力,同时研究kotlin这个现代语言的简洁性以及实现某些经典模式的便捷性。

本文只专注怎么用kotlin来进行比较特色的gof设计模式实现,基本不会探讨这些模式的思想和优缺点,需要的自行百度其它资料。本文还提供了安卓示例工程

接下来,我们先看看一些模式的实现。

策略模式

策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

  • 定义算法抽象,这里,不再是接口的方式,而是直接使用函数类型作为抽象;
typealias PlayVideo = () -> String
  • 算法实例对象,不再是类实例的方式,而是用子类型函数的方式,提供两个;
val tv: PlayVideo = {
    "用电视看视频"//作为返回值
}
val phone: PlayVideo = {
    "---用手机看视频---"
}
  • 算法的使用场景以及调用,tv和phone对象可以相互替换,产生不同行为
class Device(var name: String) {
    fun play(p: PlayVideo): String {
        return p()
    }
}
 result.text = device.play(tv)//电视播放视频
result.text = device.play(phone)//手机播放视频

整体实现思路同java类似,只是这里将函数列为了一等公民,免去了对象的创建和调用,节省代码,更易理解。

命令模式

命令模式:将请求封装成对象,以便使用不同的请求、日志、队列等来参数化其他对象。命令模式也支持撤销操作。

  • 抽象命令,声明执行的方法;
typealias command = (worker: Worker) -> Unit
  • 命令接口实现''对象'',是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作,在这里,是以函数对象的方式出现。
var strCommand: command = { it.addStr('a') }//后缀添加字符a
var numCommand: command = { it.addNum(9) }//后缀添加字符9
  • 接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
class Worker {
    var str: String = ""
    fun addStr(s: Char) {
        str += s
    }
    fun addNum(a: Int) {
        str += a
    }
    fun back() {
        str = str.substring(0, str.length - 1)
    }
}
  • 调用者,要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象,以供进行撤销、日志等操作。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
class Client(var aWorker: Worker) {
    var comList = ArrayList<command>()
    fun execute(com: command) {
        com.invoke(aWorker)
        comList.add(com)
    }
    fun undo() {
        if (comList.size == 0) {
            return
        }
        aWorker.back()
        comList.remove(comList[comList.size - 1])
    }
    fun show(): String {
        return aWorker.str
    }
}
  • 使用:创建具体的命令对象,并且设置命令对象的接收者
var client = Client(Worker())//创建调用者
client.execute(strCommand)//执行添加字符a的命令
client.execute(numCommand)//执行添加数字9的命令
client.undo()//撤销上一步的命令
观察者模式

观察者模式:有时被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

  • 定义观察者,是以函数对象的方式进行;
typealias listener=(a: Int) -> Unit
  • 被观察者,可以增加/删除观察者对象。
class Obsevable() {
    var lists: ArrayList<listener> = ArrayList()
    fun reg(p: listener) {
        lists.add(p)
    }
    fun unReg(p:listener) {
        lists.remove(p)
    }
    fun no(str: Int) {
        for (x in lists) {
            x.invoke(str)
        }
    }
}
  • 调用执行。
var observer = Obsevable()//声明被观察者对象
observer.reg { 
      result.text = "${result.text}-观察者aaa1得到事件$it"
 }//注册添加一个观察者,不能被取消注册
var v3: listener = { toast("v3得到事件$it") }//声明一个可被删除的观察者
 observer.reg(v3)//注册添加一个观察者v3
observer.notify(110)//发生事件,通知观察者
observer.unReg(v3)//删除一个观察者v3

通过函数对象的整合,代码实现更加简约。

装饰者模式

在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。不过Kotlin有强大的扩展函数功能,装饰者的实现将会比较简约。

  • 定义行为抽象和最基础的行为;
interface Text {
    fun draw(): String
}
class DefaultText(var text: String) : Text {
    override fun draw(): String {
        return text
    }
}
  • 使用扩展函数,声明几个装饰行为。
fun Text.underline(decorated: Text.() -> String): String {
    return "_" + this.decorated() + "_"
}//给已有行为添加下划线_

fun Text.bracket(decorated: Text.() -> String): String {
    return "{" + this.decorated() + "}"
}//给已有行为添加花括号{}
  • 调用执行。
var text = DefaultText("装饰者")
result.text = text.draw()//基础行为
result.text = text.underline { text.draw() }//加下划线
result.text = text.bracket { text.underline { text.draw() } }//加下划线,再加括号

通过扩展函数,动态添加某些对象的行为是不是相当方便。

整体就先列出这么几个设计模式的实现吧,眼尖的童鞋可以发现,这些设计模式基本都是行为模式,这与kotlin强大且灵活的函数功能是分不开的。而对于其它类型的某些设计模式,kotlin比较难给出比较特色的实现,以后再讨论吧。

作者刘咸尚

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

推荐阅读更多精彩内容