美文网首页KotlinJava面试
Kotlin特色风格实现gof设计模式

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

作者: CysionLiu | 来源:发表于2017-06-24 20:21 被阅读121次

    虽然设计模式偏重于思想层面,但是不同的编程语言有着其独特的语法展现,这使得在某个特定语言内,可能会更灵活和更有张力的实现某些设计模式。同时,对于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比较难给出比较特色的实现,以后再讨论吧。

    作者刘咸尚

    相关文章

      网友评论

        本文标题:Kotlin特色风格实现gof设计模式

        本文链接:https://www.haomeiwen.com/subject/lqxeqxtx.html