Kotlin特色風格實現gof設計模式

雖然設計模式偏重于思想層面,但是不同的編程語言有著其獨特的語法展現滴劲,這使得在某個特定語言內攻晒,可能會更靈活和更有張力的實現某些設計模式。同時班挖,對于kotlin來說鲁捏,由于其完全兼容Java,若是只是談設計模式的實現的話萧芙,完全可以把java實現的設計模式convert成kotlin就可以了给梅,但是這樣的話假丧,便會埋沒一些kotlin的特色。

Kotlin對比java而言动羽,其大大擴大了函數的靈活性:高階函數(可以接受函數作為參數)包帚,擴展函數(在一個類的外面,為其聲明新的方法运吓,靜態(tài)編譯渴邦,實例調用)以及獨立函數(不依賴于類/對象,可以獨立存在于文件中)等等拘哨,這使得其實現設計模式有其獨特的風格和張力谋梭,因此,本文的目的倦青,不僅僅是簡單的用kotlin實現設計模式瓮床,而是專注于發(fā)現kotlin語言的特色風格和張力,同時研究kotlin這個現代語言的簡潔性以及實現某些經典模式的便捷性姨夹。

本文只專注怎么用kotlin來進行比較特色的gof設計模式實現纤垂,基本不會探討這些模式的思想和優(yōu)缺點矾策,需要的自行百度其它資料磷账。本文還提供了安卓示例工程

接下來贾虽,我們先看看一些模式的實現逃糟。

策略模式

策略模式定義了一系列的算法,并將每一個算法封裝起來蓬豁,而且使它們還可以相互替換绰咽。策略模式讓算法獨立于使用它的客戶而獨立變化。

  • 定義算法抽象地粪,這里取募,不再是接口的方式,而是直接使用函數類型作為抽象蟆技;
typealias PlayVideo = () -> String
  • 算法實例對象玩敏,不再是類實例的方式,而是用子類型函數的方式质礼,提供兩個旺聚;
val tv: PlayVideo = {
    "用電視看視頻"http://作為返回值
}
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類似砰粹,只是這里將函數列為了一等公民,免去了對象的創(chuàng)建和調用造挽,節(jié)省代碼碱璃,更易理解弄痹。

命令模式

命令模式:將請求封裝成對象,以便使用不同的請求嵌器、日志界酒、隊列等來參數化其他對象。命令模式也支持撤銷操作嘴秸。

  • 抽象命令毁欣,聲明執(zhí)行的方法;
typealias command = (worker: Worker) -> Unit
  • 命令接口實現''對象''岳掐,是“虛”的實現凭疮;通常會持有接收者,并調用接收者的功能來完成命令要執(zhí)行的操作串述,在這里执解,是以函數對象的方式出現。
var strCommand: command = { it.addStr('a') }//后綴添加字符a
var numCommand: command = { it.addNum(9) }//后綴添加字符9
  • 接收者纲酗,真正執(zhí)行命令的對象衰腌。任何類都可能成為一個接收者,只要它能夠實現命令要求實現的相應功能觅赊。
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)
    }
}
  • 調用者右蕊,要求命令對象執(zhí)行請求,通常會持有命令對象吮螺,可以持有很多的命令對象饶囚,以供進行撤銷、日志等操作鸠补。這個是客戶端真正觸發(fā)命令并要求命令執(zhí)行相應操作的地方萝风,也就是說相當于使用命令對象的入口。
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
    }
}
  • 使用:創(chuàng)建具體的命令對象紫岩,并且設置命令對象的接收者
var client = Client(Worker())//創(chuàng)建調用者
client.execute(strCommand)//執(zhí)行添加字符a的命令
client.execute(numCommand)//執(zhí)行添加數字9的命令
client.undo()//撤銷上一步的命令
觀察者模式

觀察者模式:有時被稱作發(fā)布/訂閱模式规惰,觀察者模式定義了一種一對多的依賴關系,讓多個觀察者對象同時監(jiān)聽某一個主題對象泉蝌。這個主題對象在狀態(tài)發(fā)生變化時歇万,會通知所有觀察者對象,使它們能夠自動更新自己梨与。

  • 定義觀察者堕花,是以函數對象的方式進行;
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)
        }
    }
}
  • 調用執(zhí)行。
var observer = Obsevable()//聲明被觀察者對象
observer.reg { 
      result.text = "${result.text}-觀察者aaa1得到事件$it"
 }//注冊添加一個觀察者,不能被取消注冊
var v3: listener = { toast("v3得到事件$it") }//聲明一個可被刪除的觀察者
 observer.reg(v3)//注冊添加一個觀察者v3
observer.notify(110)//發(fā)生事件壕曼,通知觀察者
observer.unReg(v3)//刪除一個觀察者v3

通過函數對象的整合苏研,代碼實現更加簡約。

裝飾者模式

在不必改變原類文件和使用繼承的情況下腮郊,動態(tài)地擴展一個對象的功能摹蘑。它是通過創(chuàng)建一個包裝對象,也就是裝飾來包裹真實的對象轧飞。

裝飾模式會導致設計中出現許多小類,如果過度使用,會使程序變得很復雜衅鹿。不過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() + "}"
}//給已有行為添加花括號{}
  • 調用執(zhí)行泵三。
var text = DefaultText("裝飾者")
result.text = text.draw()//基礎行為
result.text = text.underline { text.draw() }//加下劃線
result.text = text.bracket { text.underline { text.draw() } }//加下劃線,再加括號

通過擴展函數衔掸,動態(tài)添加某些對象的行為是不是相當方便烫幕。

整體就先列出這么幾個設計模式的實現吧,眼尖的童鞋可以發(fā)現敞映,這些設計模式基本都是行為模式较曼,這與kotlin強大且靈活的函數功能是分不開的。而對于其它類型的某些設計模式驱显,kotlin比較難給出比較特色的實現诗芜,以后再討論吧。

作者劉咸尚

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末埃疫,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子孩哑,更是在濱河造成了極大的恐慌栓霜,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件横蜒,死亡現場離奇詭異胳蛮,居然都是意外死亡,警方通過查閱死者的電腦和手機丛晌,發(fā)現死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門仅炊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人澎蛛,你說我怎么就攤上這事抚垄。” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵呆馁,是天一觀的道長桐经。 經常有香客問我,道長浙滤,這世上最難降的妖魔是什么阴挣? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮纺腊,結果婚禮上畔咧,老公的妹妹穿的比我還像新娘。我一直安慰自己揖膜,他們只是感情好盒卸,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著次氨,像睡著了一般蔽介。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上煮寡,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天虹蓄,我揣著相機與錄音,去河邊找鬼幸撕。 笑死薇组,一個胖子當著我的面吹牛,可吹牛的內容都是我干的坐儿。 我是一名探鬼主播律胀,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼貌矿!你這毒婦竟也來了炭菌?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤逛漫,失蹤者是張志新(化名)和其女友劉穎黑低,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體酌毡,經...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡克握,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了枷踏。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片菩暗。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡旭蠕,死狀恐怖停团,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情客蹋,我是刑警寧澤塞蹭,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布番电,位于F島的核電站,受9級特大地震影響辆琅,放射性物質發(fā)生泄漏漱办。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一婉烟、第九天 我趴在偏房一處隱蔽的房頂上張望娩井。 院中可真熱鬧,春花似錦似袁、人聲如沸洞辣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扬霜。三九已至,卻和暖如春而涉,著一層夾襖步出監(jiān)牢的瞬間著瓶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工啼县, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留材原,地道東北人。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓季眷,卻偏偏與公主長得像余蟹,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子瘟裸,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內容