設(shè)計模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設(shè)計經(jīng)驗(yàn)的總結(jié)。使用設(shè)計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。 毫無疑問,設(shè)計模式于己于他人于系統(tǒng)都是多贏的;設(shè)計模式使代碼編制真正工程化;設(shè)計模式是軟件工程的基石脈絡(luò),如同大廈的結(jié)構(gòu)一樣。
前言
軟件工程中的23種設(shè)計模式,相信大家耳熟能詳,在大Java中完美適用,直接上圖(自己畫的):

這里主要給大家介紹一下神奇且常見的觀察者模式,及其引申出的一些強(qiáng)大用法:CallBack,EventBus,RxJava。
觀察者模式
觀察者模式(Observer)完美的將觀察者和被觀察的對象分離開,定義了對象間的一種一對多的依賴關(guān)系,以便一個對象的狀態(tài)發(fā)生變化時,所有依賴于它的對象都得到通知并自動刷新。
簡單的來說,打個比方,就類似于獄警時時刻刻盯著犯人,犯人作出一點(diǎn)小動作,那么獄警便立馬做出回應(yīng),反之則相安無事。在Android中的點(diǎn)擊事件監(jiān)聽setOnClickListener( )便完成對接這一概念,即:觀察者將自己注冊到被觀察對象中,被觀察對象將觀察者存放在一個容器里。被觀察對象發(fā)生了某種變化時,從容器中得到所有注冊過的觀察者,將變化通知觀察者從而達(dá)到一個時時監(jiān)聽的作用。
觀察者(Observer)模式,又叫做發(fā)布訂閱(Publish/Subscribe)模式,下面給出一張經(jīng)典的觀察者模式的關(guān)系對應(yīng)圖,看完大致都明白了吧~

強(qiáng)大的應(yīng)用之處
觀察者模式相信大家都有了一個了解,在Android中最基本的實(shí)現(xiàn)就是對點(diǎn)擊事件的監(jiān)聽了,相信網(wǎng)上關(guān)于觀察者與setOnClickListener( )的關(guān)系介紹有很多很多咯,這里介紹兩種更高級的應(yīng)用場景,看完你便會完美體會到其強(qiáng)大之處!

-
EventBus
EventBus是Android下高效的發(fā)布/訂閱事件總線機(jī)制。是基于JVM內(nèi)部的數(shù)據(jù)傳輸系統(tǒng),其核心對象為Event和EventHandler。作用是可以代替?zhèn)鹘y(tǒng)的Intent,Handler,Broadcast或接口函數(shù)在Fragment,Activity,Service,線程之間傳遞消息,優(yōu)點(diǎn)是開銷小,代碼更優(yōu)雅,以及將發(fā)送者和接收者解耦。
看完概念是不是感覺強(qiáng)大的EventBus已經(jīng)無所不能了!那么就從源碼層面分析下其強(qiáng)大的原因:
汗!在看源碼之前還是先看一下用法吧:
0、Prepare:
Gradle:
compile 'org.greenrobot:eventbus:3.0.0'
Maven:
<dependency>
<groupId>org.greenrobot</groupId>
<artifactId>eventbus</artifactId>
<version>3.0.0</version>
</dependency>
1、定義關(guān)系:寫一個類描述被觀察者和觀察者之間統(tǒng)一事件關(guān)系,可以為空,也可以加上參數(shù)并通過get/set方法綁定。
public class Event {
public Event() {
// TODO
}
}
2、接收事件頁面:注冊與銷毀。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 注冊EventBus
EventBus.getDefault().register(this);
}
// TODO
@Override
protected void onDestroy(){
super.onDestroy();
// 銷毀EventBus
EventBus.getDefault().unregister(this);
}
3、發(fā)布事件頁面:將之前定義在事件關(guān)系的類發(fā)布。
EventBus.getDefault().post(new Event());
4、接收事件頁面:重寫onEvent...( )方法,通過注解的方法鑒別類型,接收消息(4種方式)。
@Subscribe(threadMode = ThreadMode.MainThread)
//在ui線程執(zhí)行
public void onEvent(Event event) {
// TODO
}
@Subscribe(threadMode = ThreadMode.BackgroundThread)
//在后臺線程執(zhí)行
public void onEvent(Event event) {
// TODO
}
@Subscribe(threadMode = ThreadMode.Async)
//強(qiáng)制在后臺執(zhí)行
public void onEvent(Event event) {
// TODO
}
@Subscribe(threadMode = ThreadMode.PostThread)
//默認(rèn)方式, 在發(fā)送線程執(zhí)行
public void onEvent(Event event) {
// TODO
}
綜上,一個Event就對應(yīng)一個關(guān)系,在發(fā)布與接收者之間通過該標(biāo)識的Event就可以自動識別作出響應(yīng)。參考一下3.0之前在接收頁面的接收方法,對應(yīng)上面的(注:在EventBus3.0已經(jīng)將原有的方法改版):
- onEventMainThread():
不論事件是在哪個線程中發(fā)布出來的,onEventMainThread都會在UI線程中執(zhí)行。
在Android中只能在UI線程中更新UI,所以在onEvnetMainThread方法中是不能執(zhí)行耗時操作的。
- onEventBackgroundThread():
如果事件是在UI線程中發(fā)布出來的,那么onEventBackground就會在子線程中運(yùn)行。
如果事件本來就是子線程中發(fā)布出來的,那么onEventBackground函數(shù)直接在該子線程中執(zhí)行。
- onEventAsync():
無論事件在哪個線程發(fā)布,都會創(chuàng)建新的子線程在執(zhí)行onEventAsync()。
- onEvent():
發(fā)布事件和接收事件線程在同一個線程。
使用這個方法時,在onEvent方法中不能執(zhí)行耗時操作。
如果執(zhí)行耗時操作容易導(dǎo)致事件分發(fā)延遲。
下面簡單分析一下源碼,參考了鴻洋大神的帖子,從register( )方法入手,先看getDefault( ):
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
使用了雙重判斷的方式,防止并發(fā)的問題,還能極大的提高效率。再看一下普通的register( )方法:
public void register(Object subscriber) {
register(subscriber, DEFAULT_METHOD_NAME, false, 0);
}
public void register(Object subscriber, int priority) {
register(subscriber, DEFAULT_METHOD_NAME, false, priority);
}
public void registerSticky(Object subscriber) {
register(subscriber, DEFAULT_METHOD_NAME, true, 0);
}
public void registerSticky(Object subscriber, int priority) {
register(subscriber, DEFAULT_METHOD_NAME, true, priority);
}
再點(diǎn)進(jìn)去看看內(nèi)部核心的register(subscriber...)方法:
private synchronized void register(Object subscriber, String methodName, boolean sticky, int priority) {
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass(), methodName);
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod, sticky, priority);
}
}
即遍歷該類內(nèi)部所有方法,然后根據(jù)methodName去匹配,匹配成功的封裝成SubscriberMethod,最后返回一個List。繼續(xù)深入的subscribe( )方法在這里就不貼代碼了,有興趣的童鞋可以自己無限往下點(diǎn)點(diǎn)看。
register( )方法的核心便是:掃描了所有的方法,把匹配的方法最終保存在subscriptionsByEventType( )中,該方法中的eventType是我們方法參數(shù)的Class,Subscription中則保存著subscriber,subscriberMethod(method, threadMode, eventType),priority,包含了執(zhí)行改方法所需的一切。
其余的一些post( )方法等其實(shí)的本質(zhì)與上方類似,關(guān)于整個EventBus的流程可以大致梳理如下:EventBus負(fù)責(zé)訂閱對象與事件的管理,比如注冊、注銷以及發(fā)布事件等。在初始時將某個對象注冊到EventBus中,EventBus會遍歷該對象class中的所有方法,把參數(shù)數(shù)量為1且用了Subscriber注解標(biāo)識的函數(shù)管理起來,以事件類型和訂閱函數(shù)Subscriber的tag構(gòu)建一個EventType作為一種事件類型,某個事件類型對應(yīng)有一個接收者列表。當(dāng)有事件發(fā)布時,EventBus會根據(jù)發(fā)布的事件類型與tag構(gòu)建EventType,然后找到對應(yīng)的訂閱者列表,并且將這些事件投遞給所有訂閱者。SubscriberMethodHunter負(fù)責(zé)查找合適的EventType,而EventHandler則負(fù)責(zé)將這些訂閱函數(shù)執(zhí)行到相應(yīng)的線程中。
-
RxJava
Reactive Extensions編程簡稱Rx編程,又叫響應(yīng)式編程,提供一致的編程接口,幫助開發(fā)者更方便的處理異步數(shù)據(jù)流,使軟件開發(fā)更高效、更簡潔。其中,對于異步錯誤處理,傳統(tǒng)的try/catch沒辦法處理異步計算,Rx提供了合適的錯誤處理機(jī)制輕松使用并發(fā)。而Rx的Observables和Schedulers讓開發(fā)者可以擺脫底層的線程同步和各種并發(fā)問題。
關(guān)于RxJava的基本實(shí)現(xiàn)很簡單,看如下三步:
1、創(chuàng)建一個Observable對象,直接調(diào)用Observable.create( ):
Observable<String> myObservable = Observable.create(
new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> sub) {
sub.onNext("Hello, world!");
sub.onCompleted();
}
}
);
2、創(chuàng)建一個Subscriber來處理Observable對象發(fā)出的字符串:
Subscriber<String> mySubscriber = new Subscriber<String>() {
@Override
public void onNext(String s) {
System.out.println(s);
}
@Override
public void onCompleted() {
// TODO
}
@Override
public void onError(Throwable e) {
// TODO
}
};
3、通過subscribe函數(shù)就可以將myObservable對象和mySubscriber對象關(guān)聯(lián)綁定起來,完成subscriber對observable的訂閱:
myObservable.subscribe(mySubscriber);
當(dāng)然,強(qiáng)大的RxJava提供了一些方法使代碼簡化,如just( ),map( ),Action1類等等,如:
Observable.just("Hello, world!")
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
System.out.println(s);
}
});
Observable.just("Hello, world!")
.map(new Func1<String, String>() {
@Override
public String call(String s) {
return s + "Ivor";
}
}).subscribe(new Action1<String>() {
@Override
public void call(String s) {
System.out.println(s);
}
});
關(guān)于RxJava的基本使用大致就介紹到這里,后續(xù)關(guān)于RxJava和Retrofit以及RxAndroid的引申下期會更新,大家也可以提前參考一下福生寶寶的RxJava 的使用與理解(二)。
-
EventBus VS RxJava
RxJava要比EventBus的應(yīng)用更廣泛,EventBus僅僅是作為一種消息的傳遞工具,但是RxJava里面幾乎可以做任何事情,只是對于簡單的業(yè)務(wù)來說可能有些冗余,EventBus相對來說更加輕量,EventBus有個缺點(diǎn)就是凡是使用了EventBus的類都不能進(jìn)行混淆了,否則Evnetbus就找不到OnEvent方法了。
尾聲
關(guān)于觀察者模式的應(yīng)用有很多,這里先介紹這么兩種強(qiáng)大的庫,供大家參考學(xué)習(xí)~~請將強(qiáng)大的Observer與Listener發(fā)揮到極致:)
附在線流程圖制作網(wǎng)站
https://www.processon.comAndroid EventBus源碼解析 帶你深入理解EventBus
http://blog.csdn.net/lmj623565791/article/details/40920453RxJava 的使用與理解(一)
http://m.itdecent.cn/p/f564104958b8Github地址:
https://github.com/IvorfasonGithub博客:
http://ivorfason.github.io個人網(wǎng)站:
http://www.ivorfason.site個人郵箱:(我覺得QQ郵箱很高大上,You can you up?。?/strong>
justforyouymr@qq.com雜談一下
這里只是簡單的給大家介紹了一下用法和基本的實(shí)現(xiàn)方式,大家可以直接拿來寫Demo,在實(shí)際應(yīng)用中,一個簡單的EventBus便可省去許多代碼,一個簡單的RxJava便可省去許多邏輯,但是自己寫的時候還會有一些坑要踩,合理地應(yīng)用好觀察者模式,你會變得很強(qiáng)大!You can you up!