一不小心,小明在《跟著貝爾去冒險》這個真人秀節目中看到了“一日警察,一世警察”的Laughing哥,整個節目除了貝爾吃牛睾丸都不用刀叉的不雅餐飲文化外,還是鏡頭少普通話跟小明一樣爛的Laughing Sir那種冷靜和沉著穩定留下了深刻印象,不由想起電視劇《學警狙擊》中為了不暴露鐘立文的身份,要求向自己補一槍的警匪臥底巅峰推動者--Laughing 哥。
那麼,臥底這樣的工作,在我們程序裡有沒有呢?答案是肯定的,觀察者模式。
KVC全稱Key-value coding.
一個非正式的Protocol,提供一種機制來間接訪問對象的屬性.
官方文檔提供對KVC很准確的描述
Key-value coding is a mechanism for accessing an object’s properties indirectly, using strings to identify properties, rather than through invocation of an accessor method or accessing them directly through instance variables. In essence, key-value coding defines the patterns and method signatures that your application’s accessor methods implement.
KVO全稱Key-Value Observing。
典型的觀察者模式承載者。
基於監控鍵值發生變化,通知觀察者。
KVO 就是基於 KVC 實現的關鍵技術之一。
官方文檔提供對KVO很准確的描述
Key-value observing provides a mechanism that allows objects to be notified of changes to specific properties of other objects. It is particularly useful for communication between model and controller layers in an application.
Laughing哥上場了,先看看怎麼做臥底,首先,Laughing哥先得符合古惑仔行為准則混入黑幫;接著,除了放高利貸和Disco業務外最重的是擠兌從台灣出獄的世孝,選擇站在亦天內心的一邊得到足夠多的信任;最後,憑借“一日警察,一世警察”赤誠初心,秉公執法端掉亦天和制毒窩點。
那麼,你覺度Laughing Sir的作用是什麼?
1. 接近需要得到信息隱秘或不隱秘的使用場所。
2. 直接監視信息的變化。
3. 當產生了有用的信息後,那馬上通知匯報。
如果亦天制作的毒品比作信息,普通警察只能通過get方式屬性,更重要是不知道他什麼時候發生了變化。臥底Laughing Sir完美扮演的就是KVC和KVO機制,為什麼說完美?KVC是可以直接通過路徑獲取對應的鍵的值,KVO的觀察通知部分就對應Laughing Sir的監視和匯報,如果Laughing Sir變節了或者沒有意志做下去了,那就只能是KVC能獲取到信息,但不能通知上級信息的變化,就沒有了一個經典的臥底角色Laughing了。
Sun公司早早就把觀察者模式視為重要的模式,並在Java中提供方便的接口Observer和類Observable。這個地方注意一下,Observer是一個接口,Observable是一個類。因為很容易先入為主,XXXable第一反應是接口。如果看過《設計模式之禅》這本書的人,自然想起書中舉的例子是李斯監視同窗韓非子的一舉一動匯報給秦始皇。並且書中的Observer和Observable自定義定義剛好相反,注意下即可。為什麼提Java,繼續看吧。
警官:梁笑棠,從今天開始 ,你的生命屬於社會的,清楚嗎? Laughing Sir:清楚。 警官:出了這個學堂,你要叫Laughing 哥,記好了嗎? Laughing Sir:Yes sir。 警官:你妹,大聲點。 Laughing Sir:_____
程序中,Laughing Sir被派於臥底工作前,需要把Laughing Sir
的名字屬性值更換成Laughing哥
.我們就從這個地方開始練練手預熱做臥底的體驗吧。
①通過路徑方式獲取屬性值
NSString *preName = [laughingSir valueForKey:@"name"];
②修改屬性值
[laughingSir setValue:@"laughing 哥" forKey:@"name"];
NSString* exchangeName(LaughingSir *laughingSir){ NSString *preName = [laughingSir valueForKey:@"name"]; NSLog(@"laughing的舊名字:%@",preName); [laughingSir setValue:@"laughing 哥" forKey:@"name"]; NSString *newName = [laughingSir valueForKey:@"name"]; NSLog(@"laughing的新名字:%@",newName); return newName; }
亦天可能進行制毒。。。 Laughing Sir開始監控亦天 報告上級亦天制毒數:___
程序中,Laughing Sir開始觀察YiTian這個實體類中的narcotics屬性,一旦亦天制作出毒品,就馬上observeValueForKeyPath通知上級,看看如下的具體實現。
①對被觀察者添加觀察
[self.yiTian addObserver:self forKeyPath:@"narcotics" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:nil];
②實現觀察結果處理方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ //匯報上級 }
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ if([keyPath isEqualToString:@"narcotics"]){ NSNumber *narcoticsN = [change objectForKey:@"new"];//修改之後的最新值 NSInteger narcotics = [narcoticsN integerValue]; if (narcotics>0) { if (self.delegate!=nil&&[self.delegate respondsToSelector:@selector(reportYitian:)]) { [self.delegate reportYitian:narcotics]; } } } }
注意:留意下[change objectForKey:@"new"]其中這個new是指新賦予narcotics這個屬性的值,當然也有一個old而不是[change objectForKey:@"narcotics"];narcotics是毒品意思。
這裡我就直接顯示關鍵代碼了,不做過多說明,對比了解和學習。
/** * 亦天實體類 * @author minggo * @time 2016年4月1日 上午10:24:15 */ public class YITian extends Observable { private Observer observer; private int narcotics; @Override public synchronized void addObserver(Observer o) { super.addObserver(o); this.observer = o; } public void MakeNarcotics(){ for (int i = 0; i <3; i++) { narcotics++; if (observer!=null) { observer.update(this, narcotics); } } } }
留意Laughing Sir實體類的@override方法
/** * Laughing Sir實體類 * @author minggo * @time 2016年4月1日 上午9:58:36 */ public class LaughingSir implements Observer{ @Override public void update(Observable o, Object arg) { if (o instanceof YITian) { System.out.println("監視到亦天制毒"+arg+"kg"); } } public void watchOverYiTian(YITian yiTian){ yiTian.addObserver(this); } }
最後是測試main方法
/** * 觀察者模式 * @author minggo * @time 2016年4月1日 上午10:36:37 */ public class TestOberving { public static void main(String[] args) { YITian yiTian = new YITian(); LaughingSir laughingSir = new LaughingSir(); //Laughing Sir臥底開始監視亦天的一舉一動 laughingSir.watchOverYiTian(yiTian); System.out.println("Laughing Sir臥底開始監視亦天的一舉一動"); System.out.println("-----------亦天開始制作毒品--------"); //亦天開始制毒 yiTian.MakeNarcotics(); System.out.println("-----------亦天結束制作毒品--------"); } }
就猶如Laughing哥這樣的角色,觀察者模式在實際應用中起到重要的作用。無論你之前發現了,還是現在察覺到它的不可忽視。移動開發的MVVM開發架構思想中的重要解耦頁面部分,就是觀察者模式實現數據綁定,即時刷新數據。這個在iOS中KVO和Android使用Java的Observer接口都異曲同工之意,RxJava的響應是編程的基本思想也是觀察者模式之藝術。
現狀下的熱門的移動開發的關鍵字,透漏出觀察者模式顯得越來越重要。其中就包括面試門檻,曾經面試過Android開發者還是iOS開發者,問到觀察者這個模式可有了解?有回答iOS觀察就是KVO,Java的就是在被觀察對象添加回調接口,也有說過《設計模式之禅》中的韓非子被李斯監視的例子。
今天,有多了一個,Laughing哥臥底神話,個人感情建議使用這個例子,呵呵~。