閱讀961 返回首頁    go 技術社區[雲棲]


obj-c編程18:多對多的觀察者模式

    我們知道使用委托的設計模式可以實現一對一的通知關係,但是如果需要通知多個觀察者狀態變化又該如何呢?此時,需要實現觀察者模式之類的內容,而不是實現委托者一對一的模式。

    觀察者模式定義了一個對象可以將另一個對象注冊成自身觀察者的模式,對象被注冊成觀察者後,任何觀察者關注者事件都會在其發生時send給觀察者。obj-c中實現觀察者模式是通過NSNotificationCenter類實現的。該類為觀察者對象和事件提供了一個全局調度係統。觀察者可以向其注冊觀測係統中特定的事件;而被觀察對象,在事件發生時,也可以發布通知到NSNotificationCenter,這樣任何被觀察者對象的通知可以發送到任何觀察者對象,從而達到多對多關係的觀察者模式。

    為了完成觀察者模式,一般要完成以下幾個步驟:

1: 觀察者使用NSNotificationCenter實例方法-addObserver將自身注冊為特定事件的觀察者;

2: 觀察者要實現步驟1中注冊的回調方法;

3: 被觀察者對象要使用-postNotifiationName之類的發送方法發送消息;

4: 觀察者最終要確保在釋放時使用-removeObserver:將自己從NSNotificationCenter中移除。

下麵用杜撰的代碼來看看實際如何實現觀察者模式。代碼中狗仔隊對於明星無聊中的對話可謂是八卦之極,star的每一句話都要設法得到啊。不過從實際代碼看來,貌似明星也有意的想把這些對話內容傳播出去啊!如果不想,那就類似於<<obj-c編程17:鍵值觀察>>裏的鍵值觀察模式了哦。下麵上代碼:

#import <Foundation/Foundation.h>

#define msg(...) NSLog(__VA_ARGS__)

#define NOTIFICATION_NAME @"MY_NOTIFICATION"

@interface Star:NSObject{
	NSString *name;
}
	@property(readonly) NSString *name;
	-(void)talk:(NSString *)blabla;
@end

@implementation Star
	@synthesize name;

	-(id)initWithName:(NSString *)name_v{
		self = [super init];
		if(self){
			name = name_v;
		}
		return self;
	}

	-(void)talk:(NSString *)blabla{
		msg(@"%@ to say :%@",name,blabla);

		NSDictionary *secret = [NSDictionary dictionaryWithObject:blabla \
			forKey:@"words"];

		[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_NAME \
			object:self userInfo:secret];
	}
@end

@interface Dog:NSObject
	-(void)broadcast:(NSNotification *)note;
@end

@implementation Dog
	-(id)init{
		self = [super init];
		if(self){
			[[NSNotificationCenter defaultCenter] addObserver:self \
				selector:@selector(broadcast:) name:NOTIFICATION_NAME \
				object:nil];
		}
		return self;
	}

	-(void)broadcast:(NSNotification *)note{
		NSString *star_name = [[note object] name];
		NSString *words = [[note userInfo] objectForKey:@"words"];
		msg(@"star %@ sayed \"%@\"",star_name,words);
	}

	-(void)dealloc{
		[[NSNotificationCenter defaultCenter] removeObserver:self];
		//[super dealloc];
	}
@end

int main(int argc,char *argv[])
{
	@autoreleasepool{
		Star *star0 = [[Star alloc] initWithName:@"lucy"];
		Star *star1 = [[Star alloc] initWithName:@"jack"];
		Dog *dog = [[Dog alloc] init];

		[star0 talk:@"no shit!"];
		[star1 talk:@"that's right!"];
	}
	return 0;
}

運行結果是我們可以預料到的:

apple@kissAir: objc_src$./9

2014-08-03 21:05:11.830 9[910:507] lucy to say :no shit!

2014-08-03 21:05:11.831 9[910:507] star lucy sayed "no shit!"

2014-08-03 21:05:11.832 9[910:507] jack to say :that's right!

2014-08-03 21:05:11.832 9[910:507] star jack sayed "that's right!"


有人會說了,你這是1對多關係哦。多對多關係也很簡單,狗仔隊不止一隻啊,我們再來創建1個,改變的代碼如下:

int main(int argc,char *argv[])
{
	@autoreleasepool{
		Star *star0 = [[Star alloc] initWithName:@"lucy"];
		Star *star1 = [[Star alloc] initWithName:@"jack"];
		Dog *dog0 = [[Dog alloc] init];
		Dog *dog1 = [[Dog alloc] init];

		[star0 talk:@"no shit!"];
		[star1 talk:@"that's right!"];
	}
	return 0;
}

運行結果如下:

apple@kissAir: objc_src$./9

2014-08-03 21:32:43.513 9[973:507] lucy to say :no shit!

2014-08-03 21:32:43.514 9[973:507] star lucy sayed "no shit!"

2014-08-03 21:32:43.515 9[973:507] star lucy sayed "no shit!"

2014-08-03 21:32:43.515 9[973:507] jack to say :that's right!

2014-08-03 21:32:43.516 9[973:507] star jack sayed "that's right!"

2014-08-03 21:32:43.516 9[973:507] star jack sayed "that's right!"



最後更新:2017-04-03 05:39:41

  上一篇:go linux c 進程 pipe 通信代碼分析
  下一篇:go 【Tsinghua】列車調度(Train)