什麼是觀察者模式
什麼是觀察者模式?你曾經訂閱過報紙嗎?在訂閱報紙的時候,你不用去任何地方,只需要將你的個人地址信息以及訂閱信息告訴出版社,出版社就知道如何將相關報紙傳遞給你。這種模式的第二個名稱叫做發佈/訂閱模式。
在GoF中是這樣描述觀察者模式的——觀察者模式定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態上發生變化時,會通知所有觀察者對象,使它們能夠自動更新自己。
觀察者模式的的思想非常簡單,Subject(主題)允許別的對象——觀察者(這些對象實現了觀察者接口)對這個Subject的改變進行訂閱和取消訂閱。當Subject發生了變化——那麼Subject會將這個變化發送給所有的觀察者,觀察者就能對Subject的變化做出更新。在這裏,Subject是報紙的出版社,而觀察者則是訂閱報紙的我和你,當Subject發生變化——有新的報紙,會做出通知——將報紙發送給所有的訂閱者。
什麼時候使用觀察者模式?
當你需要將改變通知所有的對象時,而你又不知道這些對象的具體類型,此時就可以使用觀察者模式。 改變發生在同一個對象中,並在別的地方需要將相關的狀態進行更新。
iOS中觀察者模式的實現方法
在iOS中觀察者模式的實現有三種方法:Notification、KVO以及標準方法。
1.Notification
Notification - NotificationCenter機制使用了操作系統的功能。通過NSNotificationCenter可以讓對象之間進行進行通訊,這些對象相互間可以不認識。當你用一個並行的流來推送通知,或者刷新數據庫,並希望在界面中能夠看到時,這非常有用。
NotificationCenter發佈消息的方法如下所示:
1.NSNotification * broadcastMessage = [ NSNotification notificationWithName: AnyNotification object: Self ];
2.NSNotificationCenter * notificationCenter = [ NSNotificationCenter defaultCenter];
3.[NotificationCenter postNotification: broadCastMessage];
上面的代碼中,創建了一個NSNotification類型的對象,並指定名稱爲”broadcastMessage”,然後通過notificationCenter來發布這個消息。
要訂閱感興趣的對象中的相關事件,可以按照如下方法進行:
1.NSNotificationCenter * notificationCenter = [ NSNotificationCenter defaultCenter];
2.[NotificationCenter addObserver: Self selector: @ selector (update:) name: AnyNotification object: nil ];
如上代碼所示:訂閱了一個事件,並通過@selector指定了一個方法。
1.// 收到通知中心發來的通知
2.-(void)update:(NSNotification *) notification
3.{
4. if ([[notification name] isEqualToString:AnyNotification])
5. NSLog (@"成功收到通知中心發來的名爲%@的通知", AnyNotification);
6.}
下面是運行上面代碼,在控制檯輸出的內容:
1.2013-05-05 23:43:15.570 ObserverPattern[1738:c07] 成功收到通知中心發來的名爲broadcastMessage的通知
2.KVO
通過KVO,某個對象中的特定屬性發生了改變,別的對象可以獲得通知。蘋果官方文檔對KVO有了很好的解釋:Key-Value Observing Programming Guide。下面兩種方法都可以改變對象中屬性的值:
1.kvoSubj.changeableProperty = @"新的一個值";
2.
3.[kvoSubj setValue:@"新的一個值" forKey:@"changeableProperty"];
上面這種值改變的靈活性可以讓我們對鍵值進行觀察。
下面是新建的一個類KVOSubject,這個類中有一個屬性changeableProperty:
1.@interface KVOSubject : NSObject
2.
3.@property (nonatomic, strong) NSString *changeableProperty;
4.
5.@end
6.
7.@implementation KVOSubject
8.
9.@end
接着新建了另外一個類KVOObserver,通過該類可以監聽changeableProperty屬性值的改變。
1.@interface KVOObserver : NSObject
2.@end
3.
4.@implementation KVOObserver
5.
6.-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
7.{
8.NSLog(@"KVO:值發生了改變");
9.}
10.
11..@end
如上代碼所示,KVOObserver類只有一個方法observeValueForKeyPath。當changeableProperty屬性值的改變時,這個方法會被調用。下面是測試的代碼:
1.- (IBAction)btnKVOObservationTest:(id)sender {
2.KVOSubject *kvoSubj = [[KVOSubject alloc] init];
3.KVOObserver *kvoObserver = [[KVOObserver alloc] init];
4.
5.[kvoSubj addObserver:kvoObserver forKeyPath:@"changeableProperty" 6.options:NSKeyValueObservingOptionNew context:nil];
7.
8.kvoSubj.changeableProperty = @"新的一個值";
9.
10.[kvoSubj setValue:@"新的一個值" forKey:@"changeableProperty"];
11.
12.[kvoSubj removeObserver:kvoObserver forKeyPath:@"changeableProperty"];
13.}
執行上面的代碼,可以看到控制檯輸出如下結果:
1.2013-05-05 23:10:20.789 ObserverPattern[1358:c07] KVO:值發生了改變
2.2013-05-05 23:10:20.790 ObserverPattern[1358:c07] KVO:值發生了改變標準方法
3.標準方法
先來看看Gof中對觀察者模式定義的結構圖:
標準方法的實現是這樣的:Subject(主題)知道所有的觀察者,但是不知道它們的類型。下面我們就從創建Subject和Observer(觀察者)的協議(protocol)開始。
1.@protocol StandardObserver
2.-(void) valueChanged:(NSString *)valueName newValue:(NSString *) newValue;
3.@end
4.
5.@protocol StandardSubject
6.-(void) addObserver:(id) observer;
7.-(void) removeObserver:(id) observer;
8.-(void) notifyObjects;
9.@end
下面,我們來創建一個Subject的implementation (實現)
1.@interface StandardSubjectImplementation : NSObject
2.{
3. @private NSString *_valueName;
4. @private NSString *_newValue;
5.}
6.@property (nonatomic, strong) NSMutableSet *observerCollection;
7.-(void)changeValue:(NSString *)valueName andValue:(NSString *) newValue;
8.@end
9.
10.@implementation StandardSubjectImplementation
11.
12.-(NSMutableSet *) observerCollection
13.{
14. if (_observerCollection == nil)
15. _observerCollection = [[NSMutableSet alloc] init];
16.
17. return _observerCollection;
18.}
19.
20.-(void) addObserver:(id)observer
21.{
22. [self.observerCollection addObject:observer];
23.}
24.
25.-(void) removeObserver:(id)observer
26.{
27. [self.observerCollection removeObject:observer];
28.}
29.
30.-(void) notifyObjects
31.{
32. for (id observer in self.observerCollection) {
33. [observer valueChanged: _valueName newValue:_newValue];
34. }
35.}
36.
37.-(void)changeValue:(NSString *)valueName andValue:(NSString *) newValue
38.{
39. _newValue = newValue;
40. _valueName = valueName;
41. [self notifyObjects];
42.}
43.@end
接下來是Observer的implementation (實現):
1.@interface SomeSubscriber : NSObject
2.@end
3.
4.@implementation SomeSubscriber
5.-(void) valueChanged:(NSString *)valueName newValue:(NSString *)newValue
6.{
7. NSLog(@"SomeSubscriber輸出: 值 %@ 已變爲 %@", valueName, newValue);
8.}
9.@end
10.
11.@interface OtherSubscriber : NSObject
12.
13.@end
14.
15.@implementation OtherSubscriber
16.
17.-(void) valueChanged:(NSString *)valueName newValue:(NSString *)newValue
18.{
19. NSLog(@"OtherSubscriber輸出: 值 %@ 已變爲 %@", valueName, newValue);
20.}
21.@end
下面是演示的代碼:
1.StandardSubjectImplementation * subj = [[StandardSubjectImplementation alloc] init];
2.SomeSubscriber * someSubscriber = [[SomeSubscriber alloc] init];
3.OtherSubscriber * otherSubscriber = [[OtherSubscriber alloc] init];
4.
5.[Subj addObserver: someSubscriber];
6.[Subj addObserver: otherSubscriber];
7.
8.[subj changeValue:@"version" andValue:@"1.0.0"];
上面代碼運行的log如下所示:
1.2013-05-05 23:19:04.662 ObserverPattern[1459:c07] OtherSubscriber輸出: 值 version 已變爲 1.0.0
2.2013-05-05 23:19:04.664 ObserverPattern[1459:c07] SomeSubscriber輸出: 值 version 已變爲 1.0.0
本示例的代碼可以在這裏下載到:https://github.com/BeyondVincent/ios_patterns/tree/master/ObserverPattern
參考:http://maleevdimka.wordpress.com/2013/02/16/ios-patterns-observer/
PDF下載:
/cms/uploads/soft/130506/4196-130506101124.pdf |