一、緒
上篇博客和大家分享了ffmpeg的編譯流程以及在AndroidStudio中集成缨恒。最近由于對(duì)ffmpeg的涉獵進(jìn)展較慢,但是為了保持持續(xù)的狂暴之心,還是不能停止博客的更新谓晌。所以今天和大家分享一篇關(guān)于設(shè)計(jì)模式的內(nèi)容。想必有些朋友看到設(shè)計(jì)模式幾字就有點(diǎn)精神錯(cuò)亂癞揉,四肢麻木纸肉。哈哈,開(kāi)個(gè)玩笑喊熟。我不會(huì)以單純描述設(shè)計(jì)模式來(lái)表達(dá)柏肪,這樣的博客隨便一搜很多。既然要說(shuō)設(shè)計(jì)模式逊移,畢竟缺少不了實(shí)戰(zhàn)的結(jié)合预吆。
設(shè)計(jì)模式所帶來(lái)的效益是顯而易見(jiàn)的胳泉,23種設(shè)計(jì)模式體現(xiàn)了7種思想原則的守恒拐叉。大家最常用也最常聽(tīng)說(shuō)的 單例模式、原型模式扇商、工廠(chǎng)模式凤瘦、觀(guān)察者模式、建造者模式等等案铺,同樣很多模式在Android源碼或者優(yōu)秀的第三方開(kāi)源庫(kù)中體驗(yàn)的淋漓盡致蔬芥。例如圖片加載庫(kù),Glide控汉,ImageLoader等等都以getInstance的方式使用了單例模式(雙重鎖檢查機(jī)制)笔诵,Android源碼中AlertDialog使用build體現(xiàn)的建造者模式,Intent提供的clone原型模式姑子,3.0后的屬性動(dòng)畫(huà)插值器所體現(xiàn)的策略模式等等乎婿。本篇博客和大家分享一下狀態(tài)模式的定義以及實(shí)戰(zhàn)的使用。
狀態(tài)模式包含了三種定義:
(1)控制器
(2)抽象狀態(tài)或狀態(tài)接口
(3)具體狀態(tài)
怎么理解三者之間的關(guān)系呢谢翎?看下面展示圖:
上圖中,Context也就是控制器沐旨,即使用環(huán)境森逮。State即為抽象狀態(tài)或狀態(tài)接口,Concrete
State
A,B即為具體的狀態(tài)實(shí)現(xiàn)磁携,即狀態(tài)的具體行為褒侧。三者的關(guān)系顯而易見(jiàn),在Context中提供setState以注入的方式來(lái)改變不同的狀態(tài)谊迄,體現(xiàn)不同狀態(tài)下的不同行為闷供。
生活處處有設(shè)計(jì)模式鳞上。拿生活中的電視遙控器例子來(lái)說(shuō)这吻,在電視開(kāi)機(jī)狀態(tài)下,遙控器可以控制音量篙议,頻道切換等等唾糯,關(guān)機(jī)狀態(tài)下,對(duì)于電視的任何操作都不能進(jìn)行鬼贱。
此時(shí)移怯,遙控器就對(duì)應(yīng)于Context,State對(duì)應(yīng)于電視的狀態(tài)这难,具體狀態(tài)對(duì)應(yīng)于電視的開(kāi)機(jī)舟误、關(guān)機(jī):
代碼描述如下:
(1)控制器接口,定義了兩種狀態(tài)的控制姻乓。
(2)具體控制器實(shí)現(xiàn)嵌溢,實(shí)現(xiàn)狀態(tài)的切換眯牧。
(3)狀態(tài)接口
(4)開(kāi)機(jī)狀態(tài)
(5)關(guān)機(jī)狀態(tài)
在我們平時(shí)開(kāi)發(fā)的App應(yīng)用中赖草,肯定缺少不了登錄功能学少。App客戶(hù)端用戶(hù)狀態(tài)一般處于兩種狀態(tài):
(1)登錄狀態(tài)
(2)注銷(xiāo)狀態(tài)(退出本次登錄)
兩種狀態(tài)下對(duì)應(yīng)的App權(quán)限是不同的。例如秧骑,App中有商品的收藏版确、分享功能、加入購(gòu)物車(chē)乎折、支付功能等等绒疗。
用戶(hù)未登錄狀態(tài)時(shí),可以進(jìn)行商品分享操作骂澄,但不能對(duì)商品進(jìn)行支付吓蘑。反之,在用戶(hù)登錄后酗洒,即可進(jìn)行商品收藏士修,商品下單支付等操作。
一般的做法是樱衷,會(huì)在每個(gè)功能模塊下棋嘲,在業(yè)務(wù)處理前,例如在收藏功能模塊中矩桂,首先會(huì)對(duì)用戶(hù)的狀態(tài)進(jìn)行判斷沸移,如果用戶(hù)處于登錄狀態(tài),處理收藏邏輯侄榴。否則跳轉(zhuǎn)到登錄界面雹锣,提示用戶(hù)登錄。如果功能模塊較少的情況下癞蚕,還是可以接受蕊爵。
考慮一種場(chǎng)景:用戶(hù)狀態(tài)切換不同的情況下,會(huì)有多種不同的狀態(tài)操作桦山。此時(shí)需要在每個(gè)地方去做登錄狀態(tài)的判斷攒射,顯而易見(jiàn),這種方式非常繁瑣恒水。在后面的工作中会放,如果還有與用戶(hù)狀態(tài)相關(guān)的操作,都需要去作重復(fù)的業(yè)務(wù)邏輯钉凌。
偽代碼:
了解到使用一般方式的弊端后咧最,我們可以使用狀態(tài)模式來(lái)解決此問(wèn)題。經(jīng)過(guò)上面的分析,我們可以得到如下信息:
(1)用戶(hù)信息
(2)用戶(hù)狀態(tài)
(3)狀態(tài)行為
1.首先定義兩種狀態(tài)矢沿,兩種狀態(tài)對(duì)應(yīng)了不同的行為方式:
2.狀態(tài)行為管理
3.Activity中使用
分析:
首先滥搭,定義了兩個(gè)具體的狀態(tài)類(lèi),并且實(shí)現(xiàn)了不用的行為處理方式咨察。在登錄狀態(tài)下论熙,可以進(jìn)行收藏和支付福青。在未登錄狀態(tài)下摄狱,執(zhí)行收藏和支付行為時(shí),直接跳轉(zhuǎn)到登錄界面无午。
然后媒役,為了不在Activity直接操作State的行為,避免了Activity和State耦合宪迟,引入了LoginContext單例類(lèi)酣衷,以委托的方式通過(guò)狀態(tài)類(lèi)來(lái)管理State的行為和狀態(tài)。
最后在Activity中通過(guò)LoginContext來(lái)執(zhí)行具體操作:
首先默認(rèn)狀態(tài)是未登錄狀態(tài)次泽,此時(shí)點(diǎn)擊收藏和支付將跳轉(zhuǎn)到登錄界面穿仪。等點(diǎn)擊登錄后,狀態(tài)變?yōu)榈卿洜顟B(tài)意荤,點(diǎn)擊收藏或者支付將會(huì)進(jìn)行具體我邏輯處理啊片。
我們可以發(fā)現(xiàn),整體代碼邏輯上變得如此清晰玖像,去掉了重復(fù)冗余的判斷紫谷。
從上面的實(shí)戰(zhàn)中捐寥,不難發(fā)現(xiàn)笤昨。使用了狀態(tài)模式后,代碼邏輯變得清晰很多握恳,減少了不必要的代碼耦合瞒窒。同樣也可以發(fā)現(xiàn),狀態(tài)模式基本可以應(yīng)用在不同狀態(tài)下的同一行為的不同處理乡洼。減少了if else? 或者switch的狀態(tài)判斷以及邏輯耦合崇裁。但是也同樣增加了類(lèi)和對(duì)象的個(gè)數(shù)。所以還需要我們?cè)趯?shí)際運(yùn)用中根據(jù)需求來(lái)決策具體的使用方式就珠。以上部分內(nèi)容參考《Android源碼設(shè)計(jì)模式》寇壳。