Android深入透析之常用设计模式经验谈
前言:
?????? Android開發(fā)的設計模式,基本設計思想源于java的設計模式,java的設計模式有N多種,據(jù)不完全統(tǒng)計,迄今為止,網(wǎng)絡出現(xiàn)最頻繁的大概有23種。Java只是一門開發(fā)語言,學會并掌握這門語言進行代碼編寫,這是每個程序員必修的課程,但如何寫出高質(zhì)量、易維護和復用性強的代碼,那就體現(xiàn)出程序員的層次和水平了。設計模式的出現(xiàn)就是為了解決這些問題。
???????開始學習設計模式的時候,我們通常都有種將簡單問題復雜化的感覺,明明一個類N行代碼就能完成的事情,干嘛非要創(chuàng)建幾個類?又抽象又難理解的。后來隨著開發(fā)經(jīng)驗的增長,重復勞動的頻繁,終有一天頓悟,體驗到設計模式的妙用,方感慨萬千。常言,水滴石穿,做任何事都是這樣,經(jīng)驗和時間是最好的試金石,B哥老矣,前車之鑒,后車之師。閑言少敘,話轉(zhuǎn)正題,我們介紹一下常用的設計模式。
工廠模式:
???????什么是工廠模式?官方有很多解釋,我這里把我所理解的結(jié)合經(jīng)驗,詮釋給大家,我不想絞盡腦汁,抽象總結(jié)出類似于古文(JAVA編程思想)那樣難于理解的文字,也沒那個水平言簡意賅的、一針見血的總結(jié)出眾生都能看懂的解釋。只能笨鳥先飛、勤能補拙,從實踐出真知的角度出發(fā),拋磚引玉,供大家思考。公司有個這樣一個需求,在App中要使用到LBS定位來實現(xiàn)某些功能。產(chǎn)品技術(shù)一大堆開始了需求、技術(shù)確認會,當大家討論到定位是用百度API來實現(xiàn),還是用高德來實現(xiàn)。大家爭論不休,有人說百度定位不準,有人說高德定位不準,眾說紛紜。咋辦?最后,B總拍板,兩個一起用,哪個好用哪個,領導拍板了,但說了又等于沒說,咋辦?工廠模式這時候就呼之欲出了,我兩個都給你設計,代碼設個開關(guān)和參數(shù),你說用高德不爽,我改個參數(shù),就換百度,直到領導高興為止,于是代碼就產(chǎn)生了。? ? ?
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | public?class?test?{ ???????public?static?void?main(String[]?args)?{ ??????????????Location?position=?new?LocationFactory().getInstance("xiaomi"); ??????????????position.getPosition(); ??????????????position.getCityName(10,?20); ???????} } ?? class?LocationFactory{ ???????public?static?Location?getInstance(String?type){ ??????????????if("baidu".equals(type)){ ?????????????????????return?new?BaiduLocation(); ??????????????}else?{ ?????????????????????return?new?XiaoMiLocation(); ??????????????} ???????} } class?BaiduLocation?implements?Location{ ???????@Override ???????public?void?getPosition()?{ ??????????????//?TODO?Auto-generated?method?stub ??????????????System.out.println("通過百度定位獲取到當前的經(jīng)緯度是XXXXX"); ???????} ???????@Override ???????public?void?getCityName(long?lat,?long?lng)?{ ??????????????//?TODO?Auto-generated?method?stub ??????????????System.out.println("通過百度定位獲取到當前的城市是XXXXX"); ???????} } class?XiaoMiLocation?implements?Location{ ???????@Override ???????public?void?getPosition()?{ ??????????????//?TODO?Auto-generated?method?stub ??????????????System.out.println("通過小米定位獲取到當前的經(jīng)緯度是XXXXX"); ???????} ???????@Override ???????public?void?getCityName(long?lat,?long?lng)?{ ??????????????//?TODO?Auto-generated?method?stub ??????????????System.out.println("通過小米定位獲取到當前的城市是XXXXX"); ???????} } interface?Location{ ???????public?void?getPosition(); ???????public?void?getCityName(long?lat,long?lng); } |
上面的例子,較好的闡述了工廠模式的概念。LocationFactory是一個工廠類,靜態(tài)函數(shù)getInstance的參數(shù)決定了是選用百度還是高德,這樣,對于調(diào)用者來說,只需要關(guān)心你是用百度還是高德即可。Location是一個接口,它抽象出高德和百度常用的函數(shù)調(diào)用。拿定位來說,基本上常用的就是根據(jù)經(jīng)緯度查詢地址,或者定位當前所在位置獲取經(jīng)緯度。當然可能還有更多有用的函數(shù),我這里就不在列舉。有了這樣一個共性的接口,XiaoMiLocation和BaiduLocation通過實現(xiàn)它的接口就能分別滿足調(diào)用者的需求。調(diào)用者就能夠任意通過改變參數(shù),來實現(xiàn)來自不同定位API的需求。當然,如果百度和高德不爽,你完全可以使用谷歌API,只需要構(gòu)造一個GoogleLocation類并實現(xiàn)Location接口的方法即可。
???????工廠模式的應用非常廣泛,比如android的bitmap中常用的BitmapFactory類,創(chuàng)建Bitmap對象,通常使用靜態(tài)工廠方法。
單例模式:
???????什么是單例模式?單例模式的精髓主要在這個“單”字上,“單”就是一個,直接進入主題,我們通常使用“new”關(guān)鍵字創(chuàng)建一個對象,一旦“new”了,它就會開辟內(nèi)存創(chuàng)建一個對象。假設我們經(jīng)常反復創(chuàng)建的這個對象對我們來說其實都是一回事,那么我們就沒必要浪費資源和時間嘛,好比,你去外地出差在某個地方至少1天,第一次你去服務臺,服務臺給你開了間房,你高高興興的拿著鑰匙進房睡覺了。睡醒后出去辦事。完事后,你是不是直接拿著這個鑰匙直接奔你開好的房間?該不會去服務臺再去開一間吧?大道至簡,其實,細細想來,生活就是一種模式,只要你善于發(fā)現(xiàn),你就會有意外驚喜,原來都是這樣簡單。
來個例子吧,枯燥的代碼。
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public?class?Room?{ ???????public?static?Room?key; ???????public?static?void?main(String[]?args)?{ ??????????????Room?room=getKey(); ??????????????room.openDoor(); ??????????????Room?room1=getKey(); ??????????????room1.openDoor();? ???????} ???????public?static?Room?getKey(){ ??????????????if(key==null){ ?????????????????????key=new?Room(); ??????????????} ??????????????return?key; ???????}? ???????public?void?openDoor(){ ??????????????System.out.println("我打開了門......"); ???????} } |
看看上面這個例子,是不是跟我舉得賓館的例子相似?你不管多少次拿鑰匙,你都拿的是同一間房的鑰匙,不會重新給你發(fā)一把,這樣做,既節(jié)約了賓館的時間,也節(jié)約了你的時間,多好啊。再引申一點說,android開發(fā)中也常常使用到單例模式,比如網(wǎng)絡的封裝,數(shù)據(jù)庫的訪問都用到了單利的設計模式。
?
觀察者模式:
???????什么是觀察者模式?一般提到原告,必然腦子立刻聯(lián)想到被告,觀察者和被觀察者就如同原告和被告總是那么成對出現(xiàn)。觀察者模式,又被叫做訂閱模式,有訂閱者和發(fā)布者。當下IPHONE6異?;鸨?#xff0c;國內(nèi)粉絲要想購買,那必須得預定,必須到它蘋果官方去預定,填一大堆資料,交不交錢我不知道,反正得預定登記。等粉絲等到兩眼欲穿、花兒快謝了時候,它粉墨登場了,官方以高姿態(tài)從容向預定過的粉絲發(fā)售。這蘋果就是被觀察者,粉絲就是觀察者,觀察者和被觀察者之間需要建立聯(lián)系,那就是登記。登記過后,被觀察者拿捏火候覺得時機成熟的時候,就以權(quán)位者姿態(tài)向觀察者拋出繡球,觀察者迫不及待的伸出雙手牢牢抓住后,滿心歡喜的贊美蘋果的偉大和自己的慶幸。睜大眼睛盯著目標看,期待期望結(jié)果,這就是觀察者模式。
來段代碼體驗一把
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | import?java.util.ArrayList; import?java.util.List; ?? ?? public?class?MyOberver?{ ????????public?static?void?main(String[]?args)?{ ???????????????American?american=new?American(); ???????????????Chinese?chinese=new?Chinese(); ???????????????Iphone?iphone=new?Iphone(); ???????????????System.out.println("一個美國人登記購買"); ???????????????iphone.register(american); ???????????????System.out.println("一個中國人登記購買"); ???????????????iphone.register(chinese); ???????????????try?{ ??????????????????????System.out.println("經(jīng)過6個月的漫長等待..."); ?????????????????????Thread.sleep(2000); ??????????????}?catch?(InterruptedException?e)?{ ?????????????????????//?TODO?Auto-generated?catch?block ?????????????????????e.printStackTrace(); ??????????????} ???????????????iphone.notifys(); ???????} } /**觀察者*/ class?Iphone{ ???????private?List<Fensi>?list=new?ArrayList<Fensi>(); ???????public?void?register(Fensi?n){ ??????????????list.add(n); ??????????????System.out.println("又一個蘋果被預訂了,現(xiàn)在總共有:"+list.size()+"個人預訂了..."); ???????} ???????public?void?notifys(){ ??????????????System.out.println("IPHONE?6現(xiàn)在高調(diào)發(fā)售..."); ??????????????for?(Fensi?n:list)?{ ????????????????????????????n.receive(); ??????????????} ???????} } class?American?implements?Fensi{ ???????@Override ???????public?void?receive()?{ ??????????????//?TODO?Auto-generated?method?stub ??????????????System.out.println("美國人喊叫:嗯哼,有點貴...."); ???????} } class??Chinese?implements?Fensi{ ???????@Override ???????public?void?receive()?{ ??????????????//?TODO?Auto-generated?method?stub ??????????????System.out.println("中國人:我終于買到了,高興死了...."); ???????} } interface?Fensi{ ??????????????public?void?receive(); } |
運行后輸出結(jié)果:
一個美國人登記購買
又一個蘋果被預訂了,現(xiàn)在總共有:1個人預訂了...
一個中國人登記購買
又一個蘋果被預訂了,現(xiàn)在總共有:2個人預訂了...
經(jīng)過6個月的漫長等待...
IPHONE 6現(xiàn)在高調(diào)發(fā)售...
美國人喊叫:嗯哼,有點貴....
中國人:我終于買到了,高興死了....
?
這就是觀察者模式,Chinese和American都是觀察者,它們繼承了Fensi接口,具有了接收消息receive的能力,Iphone是被觀察者,是被觀察的目標,它的一舉一動,都會深深的影響Fensi們的熱情,觀察者需要在被觀察者哪里進行登記購買register,登記過后,等到時機成熟了,被觀察者會主動放出信號iphone.notifys();這樣,凡是登記過購買蘋果6的粉絲們,都會紛紛收到取貨的信息了。
?
代理模式:
什么是代理模式?代理模式在各類開發(fā)中運用的相當廣泛,不論是j2ee,android還是ios,都能看到它的身影,所以說設計模式無處不在。代理模式,字面理解就是自己不方便做或者不能做的事情,需要第三方代替來做,最終通過第三方來達到自己想要的目的或效果。舉例了:員工小李在B總公司打工,B總成天讓小李加班不給加班費,小李忍受不住了,就想去法院告B總。雖然法律上允許打官司不請律師,允許自辯。但是小李第一不熟悉法律起訴的具體流程,第二嘴比較笨,人一多腿就抖得厲害。因此,小李決定去找律師幫忙打官司。找律師打官司和自己打官司相比,有相同的地方,也有不同的地方。
相同的地方在于:
1、??都需要提交原告的資料,如姓名、年齡、事情緣由、想達到的目的。
2、??都需要經(jīng)過法院的取證調(diào)查,開庭爭辯等過程。
3、??最后拿到審判結(jié)果。
不同地方在于:
1、??小李省事了,讓專業(yè)的人做專業(yè)的事,不需要自己再去了解法院那一套繁瑣復雜的流程。
2、??把握更大了。
?
通過上面的例子,我們注意到代理模式有幾個重點。
1、??被代理的角色(小李)
2、??代理角色(律師)
3、??協(xié)議(不管是代理和被代理誰去做,都需要做的事情,抽象出來就是協(xié)議)
?
下面給個例子:
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | public?class?Proxy?{ ???????public?static?void?main(String[]?args)?{ ??????????????Employer?employer=new?Employer(); ??????????????System.out.println("我受不了了,我要打官司告老板"); ??????????????System.out.println("找律師解決一下吧......"); ??????????????Protocol?lawyerProxy=new?LawyerProxy(employer); ??????????????lawyerProxy.register("朵朵花開"); ??????????????lawyerProxy.dosomething(); ??????????????lawyerProxy.notifys(); ???????} } interface?Protocol{ ???????//登記資料 ???????public?void?register(String?name); ???????//調(diào)查案情,打官司 ???????public?void?dosomething(); ???????//官司完成,通知雇主 ???????public?void?notifys(); } //律師類 class?LawyerProxy??implements?Protocol{ ???????private?Employer?employer; ???????public?LawyerProxy(Employer?employer){ ??????????????this.employer=employer; ???????} ???????@Override ???????public?void?register(String?name)?{ ??????????????//?TODO?Auto-generated?method?stub ??????????????this.employer.register(name); ???????} ?? ???????public?void?collectInfo(){ ??????????????System.out.println("作為律師,我需要根據(jù)雇主提供的資料,整理與調(diào)查,給法院寫出書面文字,并提供證據(jù)。"); ???????} ???????@Override ???????public?void?dosomething()?{ ??????????????//?TODO?Auto-generated?method?stub ??????????????collectInfo(); ??????????????this.employer.dosomething(); ??????????????finish(); ???????} ???????public?void?finish(){ ??????????????System.out.println("本次官司打完了..............."); ?? ???????} ???????@Override ???????public?void?notifys()?{ ??????????????//?TODO?Auto-generated?method?stub ??????????????this.employer.notifys(); ???????}? } //雇主類 class?Employer?implements?Protocol{ ???????String?name=null; ???????@Override ???????public?void?register(String?name)?{ ??????????????//?TODO?Auto-generated?method?stub ??????????????this.name=name; ???????} ?? ???????@Override ???????public?void?dosomething()?{ ??????????????//?TODO?Auto-generated?method?stub ??????????????System.out.println("我是'"+this.name+"'要告B總,他每天讓我不停的加班,還沒有加班費。"); ???????} ?? ???????@Override ???????public?void?notifys()?{ ??????????????//?TODO?Auto-generated?method?stub ??????????????System.out.println("法院裁定,官司贏了,B總需要賠償10萬元精神補償費。"); ???????} ???????? } |
運行后,打印如下:
我受不了了,我要打官司告老板
找律師解決一下吧......
作為律師,我需要根據(jù)雇主提供的資料,整理與調(diào)查,給法院寫出書面文字,并提供證據(jù)。
我是'朵朵花開'要告B總,他每天讓我不停的加班,還沒有加班費。
本次官司打完了...............
法院裁定,官司贏了,B總需要賠償10萬元精神補償費。
代碼說明:
Protocol這個類就是上面所說的協(xié)議,是被代理者或者代理者共同遵守的約定。也就是說,無論是原告還是代理律師,到法院走程序,都需要做的事情。我們抽象出來,這個就是協(xié)議。
Employer這類是雇主類也稱被代理者類,它遵從Protocol協(xié)議,并實現(xiàn)了Protocol協(xié)議的三個方法,并去分別完成了具體事情。
LawyerProxy這類是代理類,它也遵從Protocol協(xié)議,與Employer不同的是,定義了一個Employer對象,通過構(gòu)造函數(shù)初始化。在實現(xiàn)的三個方法里,分別去調(diào)用被代理類的相同實現(xiàn)。就好比去模擬一個被告者,站在被告的角度上,去法院告狀。也就是說LawyerProxy代理類對所有想打官司的人開放,只要有原告進來,我就幫他打官司。值得注意的是collectInfo和finish這兩個函數(shù),請律師打官司和不請律師打官司,其實都要做同樣的事情(register、dosomething、notifys),但是至于為什么?剛才不是說了嗎,請律師的好處是省心并且專業(yè),他在做同樣的事情前提下,還會收集對你有利的證據(jù)和資料(collectInfo),以及后續(xù)事情的處理(finish)。
上面就是最普通的代理模式,引申一點,我們看到,對于被告來說,必須創(chuàng)建一個Employer類,并實例化后傳參給LawyerProxy代理類,這樣做,是不是暴漏了Employer?如果隱藏一下,對于被告來說,更智能傻瓜一點,該怎么做呢?
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | public?class?Proxy?{ ???????public?static?void?main(String[]?args)?{ ??????????????//Employer?employer=new?Employer(); ??????????????System.out.println("我受不了了,我要打官司告老板"); ??????????????System.out.println("找律師解決一下吧......"); ??????????????Protocol?lawyerProxy=new?LawyerProxy("朵朵花開");? ??????????????lawyerProxy.dosomething(); ??????????????lawyerProxy.notifys(); ???????} } interface?Protocol{ ???????//登記資料 ???????public?void?register(String?name); ???????//調(diào)查案情,打官司 ???????public?void?dosomething(); ???????//官司完成,通知雇主 ???????public?void?notifys(); } //律師類 class?LawyerProxy??implements?Protocol{ ???????private?Employer?employer; ???????public?LawyerProxy(String?name){ ??????????????if(name==null)?{ ?????????????????????System.out.println("誰告狀?逗我玩呢吧?"); ?????????????????????return; ??????????????} ??????????????if(employer==null)?employer=new?Employer(); ??????????????register(name);? ???????} ???????@Override ???????public?void?register(String?name)?{ ??????????????//?TODO?Auto-generated?method?stub ??????????????this.employer.register(name); ???????} ?? ???????public?void?collectInfo(){ ??????????????System.out.println("作為律師,我需要根據(jù)雇主提供的資料,整理與調(diào)查,給法院寫出書面文字,并提供證據(jù)。"); ???????} ???????@Override ???????public?void?dosomething()?{ ??????????????//?TODO?Auto-generated?method?stub ??????????????collectInfo(); ??????????????this.employer.dosomething(); ??????????????finish(); ???????} ???????public?void?finish(){ ??????????????System.out.println("本次官司打完了..............."); ?? ???????} ???????@Override ???????public?void?notifys()?{ ??????????????//?TODO?Auto-generated?method?stub ??????????????this.employer.notifys(); ???????}? } //雇主類 class?Employer?implements?Protocol{ ???????String?name=null; ???????@Override ???????public?void?register(String?name)?{ ??????????????//?TODO?Auto-generated?method?stub ??????????????this.name=name; ???????} ?? ???????@Override ???????public?void?dosomething()?{ ??????????????//?TODO?Auto-generated?method?stub ??????????????System.out.println("我是'"+this.name+"'要告B總,他每天讓我不停的加班,還沒有加班費。"); ???????} ?? ???????@Override ???????public?void?notifys()?{ ??????????????//?TODO?Auto-generated?method?stub ??????????????System.out.println("法院裁定,官司贏了,B總需要賠償10萬元精神補償費。"); ???????} ???????? } |
? ? ? ? 看到?jīng)]new LawyerProxy("朵朵花開"),只需要給代理類傳入簡單的名字,隱含了Employer類,代理類就會自動去創(chuàng)建一個Employer實例,模擬一個用戶繼續(xù)替你完成打官司的事情。
總結(jié)
以上是生活随笔為你收集整理的Android深入透析之常用设计模式经验谈的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据产品--浅析如何搭建维度指标系统
- 下一篇: java并发编程实践学习---java的