欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

IOS觀察者設(shè)計(jì)模式

 更新時(shí)間:2015年12月09日 14:28:00   投稿:mrr  
什么是觀察者模式 什么是觀察者模式?你曾經(jīng)訂閱過(guò)報(bào)紙嗎?在訂閱報(bào)紙的時(shí)候,你不用去任何地方,只需要將你的個(gè)人地址信息以及訂閱信息告訴出版社,出版社就知道如何將相關(guān)報(bào)紙傳遞,本文給大家介紹ios觀察者模式,感興趣的朋友一起看看吧

什么是觀察者模式?我們先打個(gè)比方,這就像你訂報(bào)紙。比如你想知道美國(guó)最近放生了些新聞,你可能會(huì)訂閱一份美國(guó)周刊,然后一旦美國(guó)有了新的故事,美國(guó)周刊就發(fā)一刊,并郵寄給你,當(dāng)你收到這份報(bào)刊,然后你就能夠了解美國(guó)最新的動(dòng)態(tài)。其實(shí)這就是觀察者模式,A對(duì)B的變化感興趣,就注冊(cè)為B的觀察者,當(dāng)B發(fā)生變化時(shí)通知A,告知B發(fā)生了變化。這是一種非常典型的觀察者的用法,我把這種使用方法叫做經(jīng)典觀察者模式。當(dāng)然與之相對(duì)的還有另外一種觀察者模式——廣義觀察者模式。

從經(jīng)典的角度看,觀察者模式是一種通知變化的模式,一般認(rèn)為只在對(duì)象發(fā)生變化感興趣的場(chǎng)合有用。主題對(duì)象知道有觀察者存在,設(shè)置會(huì)維護(hù)觀察者的一個(gè)隊(duì)列;而從廣義的角度看,觀察者模式是中傳遞變化數(shù)據(jù)的模式,需要查看對(duì)象屬性時(shí)就會(huì)使用的一種模式,主題對(duì)象不知道觀察者的存在,更像是圍觀者。需要知道主題對(duì)象的狀態(tài),所以即使在主題對(duì)象沒(méi)有發(fā)生改變的時(shí)候,觀察者也可能會(huì)去訪問(wèn)主題對(duì)象。換句話說(shuō)廣義觀察者模式,是在不同的對(duì)象之間傳遞數(shù)據(jù)的一種模式。

觀察者模式應(yīng)當(dāng)是在面向?qū)ο缶幊讨斜淮笠?guī)模使用的設(shè)計(jì)模式之一。從方法論的角度出發(fā),傳統(tǒng)的認(rèn)知論認(rèn)為,世界是由對(duì)象組成的,我們通過(guò)不停的觀察和了解就能夠了解對(duì)象的本質(zhì)。整個(gè)人類的認(rèn)知模型就是建立在“觀察”這種行為之上的。我們通過(guò)不停與世界中的其他對(duì)象交互,并觀察之來(lái)了解這個(gè)世界。同樣,在程序的世界中,我們構(gòu)建的每一個(gè)實(shí)例,也是通過(guò)不不停的與其他對(duì)象交互(查看其他對(duì)象的狀態(tài),或者改變其他對(duì)象的狀態(tài)),并通過(guò)觀察其他實(shí)例的變化并作出響應(yīng),以來(lái)完成功能。這也就是,為什么會(huì)把觀察模式單獨(dú)提出來(lái),做一個(gè)專門的剖析的原因——在我看來(lái)他是很多其他設(shè)計(jì)模式的基礎(chǔ)模式,并且是編程中極其重要的一種設(shè)計(jì)模式。

經(jīng)典觀察者模式

經(jīng)典觀察者模式被認(rèn)為是對(duì)象的行為模式,又叫發(fā)布-訂閱(Publish/Subscribe)模式、模型-視圖(Model/View)模式、源-監(jiān)聽(tīng)器(Source/Listener)模式或從屬者(Dependents)模式。經(jīng)典觀察者模式定義了一種一對(duì)多的依賴關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽(tīng)某一個(gè)主題對(duì)象。這個(gè)主題對(duì)象在狀態(tài)上發(fā)生變化時(shí),會(huì)通知所有觀察者對(duì)象,使它們能夠自動(dòng)更新自己或者做出相應(yīng)的一些動(dòng)作。在文章一開(kāi)始舉的例子就是典型觀察者模式的應(yīng)用。

而在IOS開(kāi)發(fā)中我們可能會(huì)接觸到的經(jīng)典觀察者模式的實(shí)現(xiàn)方式,有這么幾種:NSNotificationCenter、KVO、Delegate等

感知通知方式

在經(jīng)典觀察者模式中,因?yàn)橛^察者感知到主題對(duì)象變化方式的不同,又分為推模型和拉模型兩種方式。

推模型

主題對(duì)象向觀察者推送主題的詳細(xì)信息,不管觀察者是否需要,推送的信息通常是主題對(duì)象的全部或者部分?jǐn)?shù)據(jù)。推模型實(shí)現(xiàn)了觀察者和主題對(duì)象的解耦,兩者之間沒(méi)有過(guò)度的依賴關(guān)系。但是推模型每次都會(huì)以廣播的方式,向所有觀察者發(fā)送通知。所有觀察者被動(dòng)的接受通知。當(dāng)通知的內(nèi)容過(guò)多時(shí),多個(gè)觀察者同時(shí)接收,可能會(huì)對(duì)網(wǎng)絡(luò)、內(nèi)存(有些時(shí)候還會(huì)涉及IO)有較大影響。

在IOS中典型的推模型實(shí)現(xiàn)方式為NSNotificationCenter和KVO。

NSNotificationCenter

NSnotificationCenter是一種典型的有調(diào)度中心的觀察者模式實(shí)現(xiàn)方式。以NSNotificationCenter為中心,觀察者往Center中注冊(cè)對(duì)某個(gè)主題對(duì)象的變化感興趣,主題對(duì)象通過(guò)NSNotificationCenter進(jìn)行變化廣播。這種模型就是文章開(kāi)始發(fā)布訂閱報(bào)紙?jiān)贠C中的一種類似實(shí)現(xiàn)。所有的觀察和監(jiān)聽(tīng)行為都向同一個(gè)中心注冊(cè),所有對(duì)象的變化也都通過(guò)同一個(gè)中心向外廣播。

SNotificationCenter就像一個(gè)樞紐一樣,處在整個(gè)觀察者模式的核心位置,調(diào)度著消息在觀察者和監(jiān)聽(tīng)者之間傳遞。

一次完整的觀察過(guò)程如上圖所示。整個(gè)過(guò)程中,關(guān)鍵的類有這么幾個(gè)(介紹順序按照完成順序):

觀察者Observer,一般繼承自NSObject,通過(guò)NSNotificationCenter的addObserver:selector:name:object接口來(lái)注冊(cè)對(duì)某一類型通知感興趣.在注冊(cè)時(shí)候一定要注意,NSNotificationCenter不會(huì)對(duì)觀察者進(jìn)行引用計(jì)數(shù)+1的操作,我們?cè)诔绦蛑嗅尫庞^察者的時(shí)候,一定要去報(bào)從center中將其注銷了。

- (void) handleMessage:(NSNotification*)nc{
//解析消息內(nèi)容
NSDictionary* userInfo = [nc userInfo];
}
- (void) commonInit
{
//注冊(cè)觀察者
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleMessage:) name:kDZTestNotificatonMessage object:nil];
}

通知中心NSNotificationCenter,通知的樞紐。
主題對(duì)象,被觀察的對(duì)象,通過(guò)postNotificationName:object:userInfo:發(fā)送某一類型通知,廣播改變。

- (void) postMessage
{
[[NSNotificationCenter defaultCenter] postNotificationName:kDZTestNotificatonMessage object:Nil userInfo:@{}];
}

通知對(duì)象NSNotification,當(dāng)有通知來(lái)的時(shí)候,Center會(huì)調(diào)用觀察者注冊(cè)的接口來(lái)廣播通知,同時(shí)傳遞存儲(chǔ)著更改內(nèi)容的NSNotification對(duì)象。

apple版實(shí)現(xiàn)的NotificationCenter讓我用起來(lái)不太爽的幾個(gè)小問(wèn)題

在使用NSNotificationCenter的時(shí)候,從編程的角度來(lái)講我們往往不止是希望能夠做到功能實(shí)現(xiàn),還能希望編碼效率和整個(gè)工程的可維護(hù)性良好。而Apple提供的以NSNotificationCenter為中心的觀察者模式實(shí)現(xiàn),在可維護(hù)性和效率上存在以下缺點(diǎn):

每個(gè)注冊(cè)的地方需要同時(shí)注冊(cè)一個(gè)函數(shù),這將會(huì)帶來(lái)大量的編碼工作。仔細(xì)分析能夠發(fā)現(xiàn),其實(shí)我們每個(gè)觀察者每次注冊(cè)的函數(shù)幾乎都是雷同的。這就是種變相的CtrlCV,是典型的丑陋和難維護(hù)的代碼。
每個(gè)觀察者的回調(diào)函數(shù),都需要對(duì)主題對(duì)象發(fā)送來(lái)的消息進(jìn)行解包的操作。從UserInfo中通過(guò)KeyValue的方式,將消息解析出來(lái),而后進(jìn)行操作。試想一下,工程中有100個(gè)地方,同時(shí)對(duì)前面中在響應(yīng)變化的函數(shù)中進(jìn)行了解包的操作。而后期需求變化需要多傳一個(gè)內(nèi)容的時(shí)候,將會(huì)是一場(chǎng)維護(hù)上的災(zāi)難。

當(dāng)大規(guī)模使用觀察者模式的時(shí)候,我們往往在dealloc處加上一句:

[[NSNotificationCenter defaultCenter] removeObserver:self]

而在實(shí)際使用過(guò)程中,會(huì)發(fā)現(xiàn)該函數(shù)的性能是比較低下的。在整個(gè)啟動(dòng)過(guò)程中,進(jìn)行了10000次RemoveObserver操作,

@implementation DZMessage
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
....
for (int i = ; i < ; i++) {
DZMessage* message = [DZMessage new];
}

通過(guò)下圖可以看出這一過(guò)程消耗了23.4%的CPU,說(shuō)明這一函數(shù)的效率還是很低的。

這還是只有一種消息類型的存在下有這樣的結(jié)果,如果整個(gè)NotificationCenter中混雜著多種消息類型,那么恐怕對(duì)于性能來(lái)說(shuō)將會(huì)是災(zāi)難性的。

for (int i = 0 ; i < 10000; i++) {
DZMessage* message = [DZMessage new];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handle) name:[@(i) stringValue] object:nil];
}

增加了多種消息類型之后,RemoveObserver占用了啟動(dòng)過(guò)程中63.9%的CPU消耗。

而由于Apple沒(méi)有提供Center的源碼,所以修改這個(gè)Center幾乎不可能了。

改進(jìn)版的有中心觀察者模式(DZNotificationCenter)

GitHub地址 在設(shè)計(jì)的時(shí)候考慮到以上用起來(lái)不爽的地方,進(jìn)行了優(yōu)化:

將解包到執(zhí)行函數(shù)的操作進(jìn)行了封裝,只需要提供某消息類型的解包block和消息類型對(duì)應(yīng)的protocol,當(dāng)有消息到達(dá)的時(shí)候,消息中心會(huì)進(jìn)行統(tǒng)一解包,并直接調(diào)用觀察者相應(yīng)的函數(shù)。
對(duì)觀察者的維護(hù)機(jī)制進(jìn)行優(yōu)化(還未做完),提升查找和刪除觀察者的效率。
DZNotificationCenter的用法和NSNotificationCenter在注冊(cè)和注銷觀察者的地方是一樣的,不一樣的地方在于,你在使用的時(shí)候需要提供解析消息的block。你可以通過(guò)兩種方式來(lái)提供。

直接注冊(cè)的方式

[DZDefaultNotificationCenter addDecodeNotificationBlock:^SEL(NSDictionary *userInfo, NSMutableArray *__autoreleasing *params) {
NSString* key = userInfo[@"key"];
if (params != NULL) {
*params = [NSMutableArray new];
}
[*params addObject:key];
return @selector(handleTestMessageWithKey:);
} forMessage:kDZMessageTest];

實(shí)現(xiàn)DZNotificationInitDelegaete協(xié)議,當(dāng)整個(gè)工程中大規(guī)模使用觀察者的時(shí)候,建議使用該方式。這樣有利于統(tǒng)一管理所有的解析方式。

- (DZDecodeNotificationBlock) decodeNotification:(NSString *)message forCenter:(DZNotificationCenter *)center
{
if (message == kDZMessageTest) {
return ^(NSDictionary* userInfo, NSMutableArray* __autoreleasing* params){
NSString* key = userInfo[@"key"];
if (params != NULL) {
*params = [NSMutableArray new];
}
[*params addObject:key];
return @selector(handlePortMessage:);
};
}
return nil;
}

在使用的過(guò)程中為了,能夠保證在觀察者處能夠回調(diào)相同的函數(shù),可以實(shí)現(xiàn)針對(duì)某一消息類型的protocol

@protocol DZTestMessageInterface <NSObject>
- (void) handleTestMessageWithKey:(NSString*)key;
@end

這樣就能夠保證,在使用觀察者的地方不用反復(fù)的拼函數(shù)名和解析消息內(nèi)容了。

@interface DZViewController () <DZTestMessageInterface>
@end
@implementation DZViewController
....
- (void) handleTestMessageWithKey:(NSString *)key
{
self.showLabel.text = [NSString stringWithFormat:@"get message with %@", key];
}
....

KVO

KVO的全稱是Key-Value Observer,即鍵值觀察。是一種沒(méi)有中心樞紐的觀察者模式的實(shí)現(xiàn)方式。一個(gè)主題對(duì)象管理所有依賴于它的觀察者對(duì)象,并且在自身狀態(tài)發(fā)生改變的時(shí)候主動(dòng)通知觀察者對(duì)象。 讓我們先看一個(gè)完整的示例:

static NSString* const kKVOPathKey = @"key";
@implementation DZKVOTest
- (void) setMessage:(DZMessage *)message
{
if (message != _message) {
if (_message) {
[_message removeObserver:self forKeyPath:kKVOPathKey];
}
if (message) {
[message addObserver:self forKeyPath:kKVOPathKey options:NSKeyValueObservingOptionNew context:Nil];
}
_message = message;
}
}
- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqual:kKVOPathKey] && object == _message) {
NSLog(@"get %@",change);
}
}
- (void) postMessage
{
_message.key = @"asdfasd";
}
@end

完成一次完整的改變通知過(guò)程,經(jīng)過(guò)以下幾次過(guò)程:

注冊(cè)觀察者[message addObserver:self forKeyPath:kKVOPathKey options:NSKeyValueObservingOptionNew context:Nil];
更改主題對(duì)象屬性的值,即觸發(fā)發(fā)送更改的通知 _message.key = @"asdfasd";
在制定的回調(diào)函數(shù)中,處理收到的更改通知

- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqual:kKVOPathKey] && object == _message) {
NSLog(@"get %@",change);
}
}

注銷觀察者 [_message removeObserver:self forKeyPath:kKVOPathKey];

KVO實(shí)現(xiàn)原理

一般情況下對(duì)于使用Property的屬性,objc會(huì)為其自動(dòng)添加鍵值觀察功能,你只需要寫(xiě)一句@property (noatomic, assign) float age 就能夠獲得age的鍵值觀察功能。而為了更深入的探討一下,KVO的實(shí)現(xiàn)原理我們先手動(dòng)實(shí)現(xiàn)一下KVO:

@implementation DZKVOManual
- (void) setAge:(int)age
{
[self willChangeValueForKey:kKVOPathAge];
if (age !=_age) {
_age = age;
}
[self didChangeValueForKey:kKVOPathAge];
}
//經(jīng)驗(yàn)證 會(huì)先去調(diào)用automaticallyNotifiesObserversForKey:當(dāng)該函數(shù)沒(méi)有時(shí)才會(huì)調(diào)用automaticallyNotifiesObserversOfAge。這個(gè)函數(shù)應(yīng)該是編譯器,自動(dòng)增加的一個(gè)函數(shù),使用xcode能夠自動(dòng)提示出來(lái)。的確很強(qiáng)大。
//+(BOOL) automaticallyNotifiesObserversOfAge
//{
// return NO;
//}
+ (BOOL) automaticallyNotifiesObserversForKey:(NSString *)key
{
if (key ==kKVOPathAge) {
return NO;
}
return [super automaticallyNotifiesObserversForKey:key];
}
@end

首先,需要手動(dòng)實(shí)現(xiàn)屬性的 setter 方法,并在設(shè)置操作的前后分別調(diào)用 willChangeValueForKey: 和 didChangeValueForKey方法,這兩個(gè)方法用于通知系統(tǒng)該 key 的屬性值即將和已經(jīng)變更了;

其次,要實(shí)現(xiàn)類方法 automaticallyNotifiesObserversForKey,并在其中設(shè)置對(duì)該 key 不自動(dòng)發(fā)送通知(返回 NO 即可)。這里要注意,對(duì)其它非手動(dòng)實(shí)現(xiàn)的 key,要轉(zhuǎn)交給 super 來(lái)處理。

在這里的手動(dòng)實(shí)現(xiàn),主要是手動(dòng)實(shí)現(xiàn)了主題對(duì)象變更向外廣播的過(guò)程。后續(xù)如何廣播到觀察者和觀察者如何響應(yīng)我們沒(méi)有實(shí)現(xiàn),其實(shí)這兩個(gè)過(guò)程apple已經(jīng)封裝的很好了,猜測(cè)一下的話,應(yīng)該是主題對(duì)象會(huì)維護(hù)一個(gè)觀察者的隊(duì)列,當(dāng)本身屬性發(fā)生變動(dòng),接受到通知的時(shí)候,找到相關(guān)屬性的觀察者隊(duì)列,依次調(diào)用observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context來(lái)廣播更改。 還有一個(gè)疑問(wèn),就是在自動(dòng)實(shí)現(xiàn)KVO的時(shí)候,系統(tǒng)是否和我們手動(dòng)實(shí)現(xiàn)做了同樣的事情呢?

自動(dòng)實(shí)現(xiàn)KVO及其原理

我們仔細(xì)來(lái)觀察一下在使用KVO的過(guò)程中類DZMessage的一個(gè)實(shí)例發(fā)生了什么變化: 在使用KVO之前:

當(dāng)調(diào)用Setter方法,并打了斷點(diǎn)的時(shí)候:

神奇的發(fā)現(xiàn)類的isa指針發(fā)生了變化,我們?cè)镜念惤凶鯠ZMessage,而使用KVO后類名變成了NSKVONotifying_DZMessage。這說(shuō)明objc在運(yùn)行時(shí)對(duì)我們的類做了些什么。

我們從Apple的文檔Key-Value Observing Implementation Details找到了一些線索。

Automatic key-value observing is implemented using a technique called isa-swizzling. The isa pointer, as the name suggests, points to the object's class which maintains a dispatch table.This dispatch table essentially contains pointers to the methods the class implements, among other data. When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class. As a result the value of the isa pointer does not necessarily reflect the actual class of the instance. You should never rely on the isa pointer to determine class membership. Instead, you should use the class method to determine the class of an object instance.

當(dāng)某一個(gè)類的實(shí)例第一次使用KVO的時(shí)候,系統(tǒng)就會(huì)在運(yùn)行期間動(dòng)態(tài)的創(chuàng)建該類的一個(gè)派生類,該類的命名規(guī)則一般是以NSKVONotifying為前綴,以原本的類名為后綴。并且將原型的對(duì)象的isa指針指向該派生類。同時(shí)在派生類中重載了使用KVO的屬性的setter方法,在重載的setter方法中實(shí)現(xiàn)真正的通知機(jī)制,正如前面我們手動(dòng)實(shí)現(xiàn)KVO一樣。這么做是基于設(shè)置屬性會(huì)調(diào)用 setter 方法,而通過(guò)重寫(xiě)就獲得了 KVO 需要的通知機(jī)制。當(dāng)然前提是要通過(guò)遵循 KVO 的屬性設(shè)置方式來(lái)變更屬性值,如果僅是直接修改屬性對(duì)應(yīng)的成員變量,是無(wú)法實(shí)現(xiàn) KVO 的。

同時(shí)派生類還重寫(xiě)了 class 方法以“欺騙”外部調(diào)用者它就是起初的那個(gè)類。因此這個(gè)對(duì)象就成為該派生類的對(duì)象了,因而在該對(duì)象上對(duì) setter 的調(diào)用就會(huì)調(diào)用重寫(xiě)的 setter,從而激活鍵值通知機(jī)制。此外,派生類還重寫(xiě)了 dealloc 方法來(lái)釋放資源。

拉模型

拉模型是指主題對(duì)象在通知觀察者的時(shí)候,只傳遞少量信息或者只是通知變化。如果觀察者需求要更具體的信息,由觀察者主動(dòng)從主題對(duì)象中拉取數(shù)據(jù)。相比推模型來(lái)說(shuō),拉模型更加自由,觀察者只要知道有情況發(fā)生就好了,至于什么時(shí)候獲取、獲取那些內(nèi)容、甚至是否獲取都可以自主決定。但是,卻存在兩個(gè)問(wèn)題:

如果某個(gè)觀察者響應(yīng)過(guò)慢,可能會(huì)漏掉之前通知的內(nèi)容
觀察者必須保存一個(gè)對(duì)目標(biāo)對(duì)象的引用,而且還需要了解主題對(duì)象的結(jié)構(gòu),這就使觀察者產(chǎn)生了對(duì)主題對(duì)象的依賴。
可能每種設(shè)計(jì)模式都會(huì)存在或多或少的一些弊端,但是他們的確能夠解決問(wèn)題,也有更多有用的地方。在使用的時(shí)候,就需要我們權(quán)衡利弊,做出一個(gè)合適的選擇。而工程師的價(jià)值就體現(xiàn)在,能夠在紛繁復(fù)雜的工具世界中找到最有效的那個(gè)。而如果核桃沒(méi)被砸開(kāi),不是你手力氣不大的問(wèn)題,而是你選錯(cuò)了工具,誰(shuí)讓你非得用門縫夾,不用錘子呢!

當(dāng)然,上面那段屬于題外話。言歸正傳,在OBJC編程中,典型的一種拉模型的實(shí)現(xiàn)是delegate。可能很多人會(huì)不同意我的觀點(diǎn),說(shuō)delegate應(yīng)當(dāng)是委托模式。好吧,我不否認(rèn),delegate的確是委托模式的一種極度典型的實(shí)現(xiàn)方式。但是這并不妨礙,他也是一種觀察者模式。其實(shí)本來(lái)各種設(shè)計(jì)模式之間就不是涇渭分明的。在使用和解釋的時(shí)候,只要你能夠說(shuō)得通,而且能夠解決問(wèn)題就好了,沒(méi)必要糾纏他們的名字。而在通知變化這個(gè)事情上delegate的確是能夠解決問(wèn)題的。

我們來(lái)看一個(gè)使用delegate實(shí)現(xiàn)拉模型的觀察者的例子:

先實(shí)現(xiàn)一個(gè)delegate方便注冊(cè)觀察者,和回調(diào)函數(shù)

@class DZClient;
@protocol DZClientChangedDelegate <NSObject>
- (void) client:(DZClient*)client didChangedContent:(NSString*)key;
@end
@interface DZClient : NSObject
@property (nonatomic, weak) id<DZClientChangedDelegate> delegate;
@property (nonatomic, strong) NSString* key;
@end

注冊(cè)觀察者

//DZAppDelegate
DZClient* client = [DZClient new];
client.delegate = self;
client.key = @"aa";

當(dāng)主題對(duì)象的屬性發(fā)生改變的時(shí)候,發(fā)送內(nèi)容有變化的通知

@implementation DZClient
- (void) setKey:(NSString *)key
{
if (_key != key) {
_key = key;
if ([_delegate respondsToSelector:@selector(client:didChangedContent:)]) {
[_delegate client:self didChangedContent:@"key"];
}
}
}

觀察者收到主題對(duì)象有變化的通知后,主動(dòng)去拉取變化的內(nèi)容。

//DZAppDelegate
- (void) client:(DZClient *)client didChangedContent:(NSString *)key
{
if ([key isEqual: @"key"]) {
NSLog(@"get changed key %@",client.key);
}
}

廣義觀察者模式

在上面介紹了,觀察者被動(dòng)的接受主題改變的經(jīng)典意義上的觀察者模式之后,我們?cè)賮?lái)看一下廣義觀察者模式。當(dāng)然上面所講的經(jīng)典觀察者模式,也是一種一種傳遞數(shù)據(jù)的方式。廣義觀察者涵蓋了經(jīng)典觀察者模式。

往往我們會(huì)有需要在“觀察者”和“主題對(duì)象”之間傳遞變化的數(shù)據(jù)。而這種情況下,主題對(duì)象可能不會(huì)像經(jīng)典觀察者模式中的主題對(duì)象那樣勤勞,在發(fā)生改變的時(shí)候不停的廣播。在廣義觀察者模式中,主題對(duì)象可能是懶惰的,而是由觀察者通過(guò)不停的查詢主題對(duì)象的狀態(tài),來(lái)獲知改變的內(nèi)容。

我們熟悉的服務(wù)器CS架構(gòu),始終比較典型的冠以觀察者模式,服務(wù)器是伺服的,等待著客戶端的訪問(wèn),客戶端通過(guò)訪問(wèn)服務(wù)器來(lái)獲取最新的內(nèi)容,而不是服務(wù)器主動(dòng)的推送。

之所以,要提出廣義觀察者模式這樣一個(gè)概念。是為了探討一下觀察者模式的本質(zhì)。方便我們能夠更深刻的理解觀察者模式,并且合理的使用它。而且我們平時(shí)更多的將注意力放在了通知變化上面,而觀察者根本的目的是在于,在觀察者和主題對(duì)象之間,傳遞變化的數(shù)據(jù)。這些數(shù)據(jù)可能是變化這個(gè)事件本身,也可能是變化的內(nèi)容,甚至可能是一些其他的內(nèi)容。

從變化數(shù)據(jù)傳遞的角度來(lái)思考的話,能夠?qū)崿F(xiàn)這個(gè)的模式和策略實(shí)在是數(shù)不勝數(shù),比如傳統(tǒng)的網(wǎng)絡(luò)CS模型,比如KVC等等。在這里就先不詳細(xì)展開(kāi)討論了。

以上所述是本文給大家介紹的ios觀察者設(shè)計(jì)模式,希望大家喜歡。

相關(guān)文章

最新評(píng)論