Wzorzec delegation, opisuje metodę rozszerzania i ponownego wykorzystania funkcjonalności klasy bazowej poprzez tworzenie nowych klas z dodatkową funkcjonalnością, które wykorzystują instancje bazowej klasy w celu dostarczenia bazowej funkcjonalności
W inżynieria oprogramowania delegation pattern jest techniką, gdzie obiekt umożliwia przekazanie możliwości zaimplementowania pewnej bazowej funkcjonalność danego obiektu obiektowi powiązanemu.
Przykład utworzenia okna dialogowego po kliknięciu przycisku „Pokaż alert” oraz obsługi zdarzenia OK, Cancel.
@import <Foundation/CPObject.j> @implementation AppController : CPObject { CPTextField label; } - (void)applicationDidFinishLaunching:(CPNotification)aNotification { var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], contentView = [theWindow contentView]; [theWindow orderFront:self]; [self createButton:contentView]; [self createLabel:contentView]; } - (void)createButton:(CPView)contentView { var button = [[CPButton alloc] initWithFrame: CGRectMake(0, 0, 80, 18)]; // ustawienie nazwy na przycisku [button setTitle:"Pokaż alert"]; // ustawienie celu akcji na tą klasę i akcję "showAlert:" [button setTarget:self]; [button setAction:@selector(showAlert:)]; // dodanie przycisku do widoku [contentView addSubview:button]; } - (void)createLabel:(CPView)contentView { // Utworzenie pola tekstowego label = [[CPTextField alloc] initWithFrame:CGRectMake(100, 100, 300, 100)]; [label setStringValue:@"UWAGA! czekam na akcję."]; [label setFont:[CPFont systemFontOfSize:12.0]]; [label setFont:[CPFont boldSystemFontOfSize:12.0]]; // dodanie pola tekstowego do widoku [contentView addSubview:label]; } - (void)showAlert:(id)sender { var alert = [[CPAlert alloc] init]; [alert setMessageText:@"Ten przykład jest bardzo obrazowy ;]"]; /** * Delegacja, spowoduje że po kliknięciu któregokolwiek z przycisków, dodanych poniżej, * zostanie wywołana metoda 'alertDidEnd:returnCode:"' */ [alert setDelegate:self]; /** * Metoda przyjmuje następujące parametry: (bez komentarza ;)) * CPInformationalAlertStyle * CPWarningAlertStyle * CPCriticalAlertStyle */ [alert setAlertStyle:CPInformationalAlertStyle]; /** * Metoda przyjmuje następujące parametry: * CPHUDBackgroundWindowMasklub - ładny czarny dialog box * nil - zwykło a l'a Mac OS style */ [alert setWindowStyle:CPHUDBackgroundWindowMask]; // dodanie przycisku o tytule [alert addButtonWithTitle:@"OK"] [alert addButtonWithTitle:@"Cancel"] // wyświetla Alert jako okno modalne, użytkownik nie będzie mógł wchodzić w interakcję // z żadnym innym oknem [alert runModal]; } -(void)alertDidEnd:(CPAlert)theAlert returnCode:(int)returnCode { // returnCode == 0, odpowiada pierwszemu dodanemu przyciskowi tj. OK if (returnCode == 0) { [label setStringValue:@"WYBRANO: akcja po kliknięciu OK!"]; } else // returnCode == 0, odpowiada kolejno dodanemu przyciskowi tj. Cancel if (returnCode == 1) { [label setStringValue:@"WYBRANO: akcja po kliknięciu Cancel!"]; } } @end
Target-Action bardzo dobrze sprawdza się przy obsłudze pojedynczych zdarzeń na kontrolkach np.: kliknięcie przycisku, który otwiera okno dialogowe. Ale co w przypadku kilku przycisków gdzie kliknięcie dowolnego z nich wyłancza pozostałe (Przykład okna dialogowego z przyciskami OK i Cancel). Implementowanie akcji dla każdego z nich będzie nieefektywne. Rozwiązaniem w takim przypadku jest wydelegowanie obsługi zdarzenia na zewnątrz obiektu. Gdzie wywołana akcja jest rozpoznawana przez identyfikator, którym jest kolejna liczba porządkowa przypisana przyciskowi podczas jego konstruowania.