java-android設(shè)計(jì)模式學(xué)習(xí)筆記(2):觀察者模式-編程開(kāi)發(fā)技術(shù)_第1頁(yè)
java-android設(shè)計(jì)模式學(xué)習(xí)筆記(2):觀察者模式-編程開(kāi)發(fā)技術(shù)_第2頁(yè)
java-android設(shè)計(jì)模式學(xué)習(xí)筆記(2):觀察者模式-編程開(kāi)發(fā)技術(shù)_第3頁(yè)
java-android設(shè)計(jì)模式學(xué)習(xí)筆記(2):觀察者模式-編程開(kāi)發(fā)技術(shù)_第4頁(yè)
java-android設(shè)計(jì)模式學(xué)習(xí)筆記(2):觀察者模式-編程開(kāi)發(fā)技術(shù)_第5頁(yè)
已閱讀5頁(yè),還剩7頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、java/android設(shè)計(jì)模式學(xué)習(xí)筆記(2):觀察者模式-編程開(kāi)發(fā)技術(shù)java/android設(shè)計(jì)模式學(xué)習(xí)筆記(2): 觀察者模式原文出處:shawn_dut這篇來(lái)講一下觀察者模式,觀察者模式在實(shí)際項(xiàng)目屮使用的也是非常頻繁的,它 最常用的地方是gui系統(tǒng)、訂閱發(fā)布系統(tǒng)等。因?yàn)檫@個(gè)模式的一個(gè)重要作用 就是解耦,使得它們之間的依賴(lài)性更小,甚至做到毫無(wú)依賴(lài)。以gui系統(tǒng)來(lái)說(shuō), 應(yīng)用的ui具冇易變性,尤其是前期隨著業(yè)務(wù)的改變或者產(chǎn)品的需求修改,應(yīng)用 界面也經(jīng)常性變化,但是業(yè)務(wù)邏輯基本變化不大,此時(shí),gui系統(tǒng)需耍一套機(jī)制 來(lái)應(yīng)對(duì)這種情況,使得u1層與具體的業(yè)務(wù)邏輯解耦,觀察者模式此時(shí)就派上用 場(chǎng)了。

2、ps:對(duì)技術(shù)感興趣的同鞋加群544645972 -起交流。設(shè)計(jì)模式總目錄java/android設(shè)計(jì)模式學(xué)習(xí)筆記目錄特點(diǎn)觀察者模式定義了對(duì)象之間的一對(duì)多依賴(lài),這樣一來(lái),當(dāng)一個(gè)對(duì)象狀態(tài)發(fā)生改 變時(shí),它的所有依賴(lài)者都會(huì)收到通知并自動(dòng)更新。它實(shí)現(xiàn)了 subject和 observer之間的松耦合,subject只知道觀察者實(shí)現(xiàn)了 observer接口,主題 不需要知道具體的類(lèi)是誰(shuí)、做了些什么或其他任何細(xì)節(jié)。任何時(shí)候我們都可以增 加新的觀察者。因?yàn)橹黝}唯一依賴(lài)的東西是一個(gè)實(shí)現(xiàn)observer接口的對(duì)象列 表,所以我們可以隨時(shí)增加觀察者,同樣的,也可以在任何時(shí)候刪除觀察者,當(dāng) 然更不用去關(guān)心觀察者的類(lèi)型

3、,只要實(shí)現(xiàn)了 observer接口即可,subject最后 只會(huì)發(fā)通知給實(shí)現(xiàn)了 observer接口的觀察者o subject和observer之間實(shí)現(xiàn) 松耦合z后,雙方代碼的修改都不會(huì)影響到另外一方,當(dāng)然前提是雙方得遵守接 口的規(guī)范(接口隔離原則)。觀察者模式使用的場(chǎng)景:關(guān)聯(lián)行為場(chǎng)景,需要注意的是,關(guān)聯(lián)行為是可拆分的,而不是“組合"關(guān)系;事件多級(jí)觸發(fā)場(chǎng)景;跨系統(tǒng)的消息交換場(chǎng)景,如消息隊(duì)列、事件總線的處理機(jī)制。eventbus框架就是一個(gè)使用觀察者模式的典型例子。uml類(lèi)圖c-iobserver+ update (object object)ai+ update (object ob

4、ject)+ registerobserwr (iobserver observer) : void + removeobserver (iobserver observer) : void + hotifyobserver (object object) : voidaconcretesubject+ registerobserwr (iobserver observer) : void + removeobserver (iobserver observer) : void + notifyobserver (object object) : void觀察者模式的uml類(lèi)圖如上圖所示,一般

5、基本由4個(gè)角色構(gòu)成 subject:抽象主題,也就是被觀察的角色,抽彖主題把所有觀察者對(duì)彖的引用保存 在一個(gè)集合里,每個(gè)主題都可以?xún)尤我鈹?shù)雖的觀察者,抽象主題提供一個(gè)接口,可 以增加和刪除觀察者對(duì)象。 concretesubject:具體主題,該角色將有關(guān)狀態(tài)存入具體觀察者對(duì)象,在具體主題的 內(nèi)部狀態(tài)發(fā)牛改變時(shí),給所有注冊(cè)過(guò)的觀察者發(fā)出通知,具體主題角色對(duì)象乂叫做 具體被觀察者角色。 observer:抽象觀察者,該角色是觀察者的抽象類(lèi),它定義了一個(gè)更新接口,使得 在得到主題的更改通知時(shí)更新口己。 concreteobserver:具體的觀察者,該對(duì)象實(shí)現(xiàn)抽象觀察者介色所定義的更新接口, 以便

6、在主題的狀態(tài)變化時(shí)更新ti身的狀態(tài)。有幾點(diǎn)需要注意的是1. subject和observer是一個(gè)一對(duì)多的關(guān)系,也就是說(shuō)觀察者貝要實(shí)現(xiàn)observer接 口并把自己注冊(cè)到subject小就能夠接收到消息事件;2. java api 有內(nèi)置的觀察者模式類(lèi):java.util.observable 類(lèi)和 java.util.observer 接口, 這分別對(duì)應(yīng)著subject和observer的角色;3. 使川java api的觀察者模式類(lèi),需要注意的是被觀察者在調(diào)川notifyobservers() 函數(shù)通知觀察者之詢(xún)一定要調(diào)用setchanged()函數(shù),要不然觀察者無(wú)法接到通知;4. 使用j

7、ava api的缺點(diǎn)也很明顯,由于observable是一個(gè)類(lèi),java只允許單繼承的 缺點(diǎn)就導(dǎo)致你如果同吋想要獲取另一個(gè)父類(lèi)的加性吋,你只能選擇適配器模式或者 是內(nèi)部類(lèi)的方式,而且山于setchanged()函數(shù)為protected屬性,所以你除非繼承 observable類(lèi),否則你根本無(wú)法使用該類(lèi)的屬性,這也違背了設(shè)計(jì)模式的原則:多 用組合,少用繼承。示例與源碼觀察者模式行法有很多利1,只要遵循將被觀察者和觀察者解耦思想的方法都是可 以的,列舉三種我在開(kāi)發(fā)中常見(jiàn)的方法,以f i rstmoduel作為secondmodulel 和 secondmodule2 的父 module , 最后

8、application 以 secondmoduell 和 secondmodule2作為父module,形成一個(gè)菱形的關(guān)系為例:java api使用java api的寫(xiě)法其實(shí)就是使用java. util. observable類(lèi)和 java. util. observer接口,根據(jù)uml類(lèi)圖構(gòu)造觀察者,我們簡(jiǎn)單實(shí)現(xiàn)一個(gè)在 sccondmodulc2中通知secondmodulel有數(shù)據(jù)源的改變,并且讓 secondmodulel打印岀對(duì)應(yīng)日志的功能。因?yàn)閟econdmodulel和 secondmodule2是一個(gè)同級(jí)關(guān)系,所以無(wú)法相互調(diào)用,只能通過(guò)firstmodule作 為主題使用觀察者

9、模式進(jìn)行通信。subject在使用java apt時(shí)其實(shí)就是observable類(lèi),所以我們要在 firstmodulc中繼承該類(lèi)實(shí)現(xiàn)一個(gè)concrctcsubjcct用來(lái)保存所有的觀察者, 接著在secondmodulel屮實(shí)現(xiàn)observer接口來(lái)生成一個(gè)觀察者,最后在 secondmodule2中通知firstmodule數(shù)據(jù)源改變,最后通過(guò)firstmodule通知 到secondmodulel ,代碼如下:f irstmoduel/dataobservable. class?中利用單例模式進(jìn)行觀察者的管理和通 知:public class dataobservable extends

10、 observableprivate static volatile dataobservable instance;private dataobservable() public static dataobservable getlnstance() if (instance 二二 null)synchronized (dataobservable. class) if (instanee = null) instancc = new dataobservable();return instanee;public void notifydatachanged(databean data) s

11、etchanged();notifyobservers(data);firstmoduel/databean. class?數(shù)據(jù)類(lèi):public class databean public int temperature;secondmodulel/dataobserver. class?屮判斷如果為正確的 observerable 則 打卬日志:public class dataobserver implements observer private static final string tag = "dataobserver"©overridepublic

12、void update (observable observable, object data) if (observable instanceof dataobservable) if (data instanceof databean)log. e (tag, (databean) data) temperature+,z,);secondmodule2/datanotify> classpublic class datanotify public static void notifydatachanged()databean bean 二 new databean ();bean.

13、 temperature 二(int) (math, random() * 40); dataobservable. gettnstance(). notifydotachanged(bean);最后在mainactivity中調(diào)用datanotify類(lèi)的相應(yīng)方法通知dataobserver 溫度數(shù)據(jù)變更即可:©overrideprotected void oncreate(bundie savcdlnstanccstatc) dataobservable. getlnstance(). addobserver (new dataobserver ();©overridep

14、rotected void ondestroy() super. on destroy ();dataobservable. getlnstance (). deleteobserver(new dataobserver ();public void onclick(vicw v)if (v. getld () = r. id. btn_data_change_l) datanotify. notifydatachanged();最后能夠成功打印出正確日志,也就是實(shí)現(xiàn)了?android?屮兩個(gè)同級(jí)module z 間的通信。當(dāng)然如果覺(jué)得麻煩不使用java api的這兩個(gè)類(lèi),口己去實(shí)現(xiàn)的話也是完

15、全可以 的,而且有時(shí)可操縱性會(huì)比java apt更好一些。multi observer冇時(shí)候我們不一定全部要實(shí)現(xiàn)自同一個(gè)observer接口,根據(jù)實(shí)際情況我們可以 在完全解耦的情況下將多個(gè)observer注冊(cè)到subject中,并口根據(jù)情況只通 知到我們想要通知的一個(gè)observer屮,聽(tīng)起來(lái)很亂,其實(shí)看一張uml圖就清 楚了:0- observer_l= 這種方式其實(shí)最重要的就是subject這個(gè)角色了,他承擔(dān)了大部分的工作量, 我們先實(shí)現(xiàn)若干個(gè)observer的角色: firstmodule/idatalistenerone. class public interface idatalis

16、tcncrone void ondatachanged(databean data);firstmodule/idatalistenertwo. classpubl ic interface tdatalistenertwo void ondatachangcd(databcan data);非常簡(jiǎn)單的幾個(gè)接口,用來(lái)在secondmodulel和secondmodule2之間進(jìn)行通 信。接著是最重要的subject和concretesubject角色:firstmodule/imultidataobservable> classpublic interface imultidataobs

17、crvablc /*增加觀察者*/ void addobserver(object observer);/*刪除觀察者*/ void deleteobserver(object observer) throwsillegalargumentexcept ion;/*查找觀察者*/ <t>arraylist<t> findobserver(class<t> clazz);firstmodule/multidataobservable. classpublic class multidataobservable implements imultidataobse

18、rvable private static volatile muitidataobservable instanee; private arraylist<objcct> observers;private multidataobservable() observers 二 new arraylisto ();public static multidataobservable getlnstance() if (instance 二二 null) synchronized (multidataobservable. class) if (instance = null) inst

19、ance 二 new multidataobservable();1jreturn instance;©overridepublic void addobscrvcr(object observer) observers, add(observer);©overridepublic void dclctcobscrvcr(object observer) throws11legalargumentexception if (observer 二二 null) throw new ii legalargumentexcept ion (/zobserver must not

20、be nuirz);if (!observers, remove(observer) throw new 11 legalargumentexcept ion ('"observer not registered);©overridepublic <t> arraylist<t> findobserver(class<t> clazz) arraylist<t> lists 二 new arraylisto();for (object observer : observers) if (clazz. islnstanc

21、c(observer) lists.add(clazz. cast(observer);return 1 ists;這個(gè)類(lèi)主要是有三個(gè)方法,增刪找,特別是findobserver方法,它通過(guò)傳入的 class對(duì)象從觀察者1 isl中找到符合耍求的observer并且返回,需耍特別留 意的一點(diǎn)是需要使用的方法是class, islnstance(object object)方法,而不 是直接判斷object. getclasso = clazz ,因?yàn)楹笳叩倪@種判斷如果使用的是 匿名內(nèi)部類(lèi)方式,他的類(lèi)名會(huì)是datacommunicate$l這種樣式,所以這種方法 是不可行的。最后在secondm

22、odulel和secondmodule2中只要根據(jù)使用調(diào)用和 應(yīng)的方法即可,以secondmodule2為例: secondmodule2/datacommunicate. classpublic class datacommunicate private static final string tag = "'datacommunicate;private static idatalistenertwo listenertwo = null;public static void registerdatalistenertwo() imu11idataobservab1e d

23、ataobservable 二multi dataob scrvab1e. getlnstance();listenertwo = new idatalistenertwo() ©override public void ondatachanged(databean data) log.e (tag, data, temperature + “);; dataobservable. addobserver(listenertwo);public static void notifydatalistenerone() imultidataobscrvablc dataobservabl

24、e = mu11idataobservab1e. getlnstance();arraylist<idatalistenerone> lists 二 dataobservable. findobserver(idatalistenerone. class);databean bean 二 new databean();bean, tcmpcrature = (int) (math, random() * 40); for (idatalistenerone listener : lists) listener.ondatachanged(bean);public static vo

25、id unregisterdatalistenertwo() imultidataobservable dataobservable 二muitidataobservable. getlnstance();dataobservable. deleteobserver(1istenertwo);最后也可以成功通信,這種方式的優(yōu)點(diǎn)是完全可以自定義observer這個(gè)接口, 接口屮的方法可以任意定義,具有很大的自由性,便于統(tǒng)一管理所有的觀察者, 非常方便。eventbus事件總線大家想必已經(jīng)看見(jiàn)過(guò)很多了,它也是一個(gè)典型的觀察者模式用例,列舉 一下我常見(jiàn)的3個(gè)框架: greenrobot/eventb

26、 us androidenventbus otto它們?cè)硪膊粡?fù)雜,對(duì)比z類(lèi)的網(wǎng)上資料很多,比如otto框架的效率大多數(shù) 時(shí)候會(huì)比不上eventbus?等,感興趣想要具體了解的自己動(dòng)動(dòng)手收集一下,我這 里以使用最丿' 泛的greenrobot/eventbus為例,來(lái)實(shí)現(xiàn)secondmodulel和 secondmodule2之間的通信:secondmodule1/eventnotifier. classpublic class eventnotificr private static volatile eventnotifier instance;private eventmotif

27、ier() public static eventnotifier getlnstance() if (instance 二二 null) synchronized (eventnotifier. class) if (instance 二二 nul1) instancc 二 new eventnotificr();return instanee;public void sendevent() databean bean 二 new databean ();bean. temperature = (int) (math, random() * 40);eventbus. gctdcfault(

28、) post (bean);secondmodule2/event0bserver. classpublic class eventobserver private static final string tag 二 evcntobscrvcrz,; private static volatile eventobserver instance;private eventobserver()public static eventobserver getlnstance() if (instance 二二 nul1) synchronizcd (evcntobscrvcr. class) if (

29、instance = null) instance = new eventobserver(); return instancc;public void registerobserver() eventbus. getdefau11() register(this);public void unregisterobserver() eventbus.getdefault(). unregister(this);©subscribepublic void oneventmainthread(databean bean) log. e (tag, bean, temperature +

30、“);特別需要注意的是,oneventmainthread函數(shù)需要加上©subscribe注解,要不 然是無(wú)法工作。最后在mainactivity中調(diào)用相關(guān)函數(shù)即可:©overrideprotected voi d oncreate(bundle saved!nstancestate) eventobserver. getlnstance(). registerobserver ();©overrideprotccted void ondestroy() eventobserver. getlnstance (). unregisterobserver ();©overridepublic void onclick(view v) else if (v. getld ()二二 r. id. btn_data_change_3) eventnotifier. getlnstance(). sendevent();最后當(dāng)然也是能夠成功!總結(jié)觀察者模式在實(shí)際開(kāi)發(fā)過(guò)程屮使用的場(chǎng)景真的挺多,比

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論