Wzorzec obserwatora (ang. observer pattern) – wzorzec należący do grupy wzorców czynnościowych. Jest wykorzystywany w sytuacji, kiedy mamy do czynienia z pewnym modelem danych oraz kilkoma jego reprezentacjami i chcemy zachować spójność między nimi. Przykładem mogą być tu dane statystyczne oraz ich reprezentacje w postaci np. arkusza danych, wykresu słupkowego, wykresu kołowego, itp.
Przy zastosowaniu wzorca obserwatora oddzielamy logiczną strukturę danych od jej reprezentacji, unikając trwałych połączeń między klasami i umożliwiając tym samym ponowne wykorzystanie poszczególnych klas. Jednocześnie unikamy nieczytelnego i zbyt mocno rozbudowanego kodu w pojedynczej klasie.
Fragment z Wikipedii Wzorzec obserwatora
Cappuccino dostarcza framework do wysyłania wiadomości pomiędzy obiektami w procesie nazwanym „powiadomieniami”.
Obiekty zarejestrowane poprzez CPNotificationCenter będą powiadamiane gdy wysłane do nich powiadomienia CPNotifications będą spełniać pewne kryteria.
Centrum powiadomień przetwarza powiadomienia synchronicznie - czyli, zwracana jest kontrola do centrum powiadomień zaraz gdy każdy z odbiorców (obiektów obserwowanych) odbierze powiadomienie i przetworzy je.
Przykład wysyłania powiadomienia, do obiektów obserwujących, o nazwie „MySliderDidChangeValue” i obiekcie: sender (przykład z suwakami):
[[CPNotificationCenter defaultCenter] postNotificationName:@"MySliderDidChangeValue" object:sender];
Przykład rejestrowania nowych obserwujących obiektów, które będą obserwować powiadomienia o nazwie „MySliderDidChangeValue” oraz akceptować powiadomienia z dowolnego typu obiektu (object:nil).
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(resizeWindow:) name:@"MySliderDidChangeValue" object:nil];
Bardzo ciekawy wpis związany z testowaniem powiadomień można przeczytać na blogu Jerod Santo.
Inspiracja przykładu zaczerpnięta z: Cappuccino Casts
@import <Foundation/CPObject.j> @implementation AppController : CPObject { CPSlider _slider1; CPSlider _slider2; } - (void)applicationDidFinishLaunching:(CPNotification)aNotification { var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], contentView = [theWindow contentView], bounds = [contentView bounds]; // Pierwszy suwak _slider1 = [[CPSlider alloc] initWithFrame:CGRectMake(CGRectGetWidth(bounds)/2 -300 ,100, 200,16)]; [_slider1 setValue:200]; [_slider1 setMinValue:50]; [_slider1 setMaxValue:300]; [_slider1 setTarget:self]; [_slider1 setAction:@selector(sliderChangeValue:)]; [contentView addSubview:_slider1]; // Drugi suwak _slider2 = [[CPSlider alloc] initWithFrame:CGRectMake(CGRectGetWidth(bounds)/2 +10 ,100, 200,16)]; [_slider2 setValue:200]; [_slider2 setMinValue:50]; [_slider2 setMaxValue:300]; [_slider2 setTarget:self]; [_slider2 setAction:@selector(sliderChangeValue:)]; [contentView addSubview:_slider2]; // Przyciks pierwszy var button1 = [[CPButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(bounds)/2 - 300, 60, 200, 24)]; [button1 setTitle:@"Utwórz okno 1"]; [button1 setTarget:self]; [button1 setAction:@selector(createNewWindowForSlider1:)] [contentView addSubview:button1]; // Przyciks drugi var button2 = [[CPButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(bounds)/2 + 10, 60, 200, 24)]; [button2 setTitle:@"Utwórz okno 2"]; [button2 setTarget:self]; [button2 setAction:@selector(createNewWindowForSlider2:)] [contentView addSubview:button2]; [theWindow orderFront:self]; } // Metoda, do której jest wysyłana wiadomość podczas zmiany pozycji suwaka. - (void)sliderChangeValue:(id)sender { // Zmiana wartości suwaka powoduje nadanie powiadomienia // o nazwie (i identyfikatorze) "MySliderDidChangeValue" // Powiadomienie przesyła do obserwowanych obiekt również obiekt suwaka [[CPNotificationCenter defaultCenter] postNotificationName:@"MySliderDidChangeValue" object:sender]; } // Metoda, do której jest wysyłana wiadomość // podczas kliknięcia przyciku "Utwórz okno 1" - (void)createNewWindowForSlider1:(id)sender { // Tworzenie okna powiązanego z pierwszym suwakiem [self createNewWindow:sender linkedToSlider:_slider1]; } // Metoda, do której jest wysyłana wiadomość // podczas kliknięcia przyciku "Utwórz okno 2" - (void)createNewWindowForSlider2:(id)sender { // Tworzenie okna powiązanego z drugim suwakiem [self createNewWindow:sender linkedToSlider:_slider2]; } // Metoda, tworzy okno powiązane z suwakiem - (void)createNewWindow:(id)sender linkedToSlider:(CPSlider)aSlider { // wartość suwaka var value = [aSlider value]; // Tworzenie instancji okna o powiązanego z suwakiem var window = [[MyWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPHUDBackgroundWindowMask | CPClosableWindowMask linkedToSlider:aSlider]; // Ustawienie położenia x,y - powiązane z wartością suwaka [window setFrameOrigin:CGPointMake(value,value)]; // Wustawienie wysokości i szerokości - powiązane z wartością suwaka [window setFrameSize:CGSizeMake(value,value)]; [window orderFront:self]; } @end // Własna implementacja CPWindow // Umożliwia powiązanie okna z suwakiem poprzez dodanie go // do obserwowanych zdarzeń o nazwie "MySliderDidChangeValue" @implementation MyWindow : CPWindow { } // Rozszerzenie metody "initWithContentRect:styleMask:" - (id)initWithContentRect:(CGRect)aContentRect styleMask:(unsigned int)aStyleMask linkedToSlider:(CPSlider)aSlider { // Inicjujemy okno var self = [super initWithContentRect:aContentRect styleMask:aStyleMask]; if (self) { // Dodanie obiektu okna do obserwowanych powiadomień typu "MySliderDidChangeValue", // Obserwowany obiekt akceptuje tylko powiadomienia zawierające obiekt suwaka powiązanego z nim // Ustawiony jest również selektor "resizeWindow", który jest wywoływany gdy powiadomienie zostanie nadane. [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(resizeWindow:) name:@"MySliderDidChangeValue" object:aSlider]; } return self; } // Metoda do której jest wysyłana wiadomość, // podczas zaakceptowania wysyłanego powiadamiania "MySliderDidChangeValue" - (void)resizeWindow:(CPNotification)aNotification { var slider = [aNotification object]; var value = [slider value]; // zmiana wielkości okna [self setFrameSize:CGSizeMake(value,value)]; } @end;