Zpět Obsah Další

Objective C: příklad 4
Dynamické rozpoznání třídy


Čtvrtým příkladem není kompletní program, ale pouze doplněk k minulému příkladu. Uvědomme si, že v implementaci minulého příkladu se skrývalo jedno nebezpečí: poslal-li někdo objektu třídy ModMN zprávu sub: nebo add: a jako parametr této třídy zadal objekt jiné třídy než ModMN, došlo nutně k běhové chybě. Implementace zpráv add: a sub: totiž objektu, který dostane jako parametr, posílá zprávy get1 a get2; tyto zprávy jsou schopny zpracovat pouze objekty třídy ModMN. Pošleme-li objektu zprávu, kterou není schopen zpracovat, skončí program chybou.

Jistě, mohli bychom v duchu jazyka C++ deklarovat typy objektů:

@interface...
...
-
(ModMN*)add:(ModMN*)o;
-
(ModMN*)sub:(ModMN*)o;
...
@end

to by však ve skutečnosti nic neřešilo. Jistě, překladač by mohl kontrolovat, zda objekt, který metodě předáváme, je deklarován stejně; jenže bez ohledu na to jak je objekt deklarován může jeho obsahem být cokoli!

Objective C nabízí pro takové případy řadu prostředků, jež na rozdíl od nedostatečného přístupu C++ problém skutečně řeší; máme je k dispozici jako metody libovolného objektu díky dědictví po standardní třídě NSObject. Ukážeme si použití dvou z nich:

// Objective C — příklad 4
//
// dynamické rozpoznání třídy
// tento příklad ukazuje, jak se můžeme při implementaci zpráv vyrovnat
// s tím, že objekt, předaný jako parametr zprávy, nemusí být objektem
// předem (staticky) určené třídy

#import "sample3.h" // importujeme interface

@implementation ModMN // rodiče a proměnné není třeba uvádět — jsou známy z interface
... jako v příkladu 3 ...
-add:n
{
  if ([n isKindOfClass:[ModMN class]])
    return [self set:value+[n get1]:[n2 get]+[n get2]];
  else if ([n isKindOfClass:[ModN class]])
    return [self set:value+[n get]:[n2 get]+[n get]];
  else {
    printf("!!! přičítání nepoužitelného objektu !!!\n");
    return self;
  }
}
-sub:n
{
  if ([n respondsToSelector:@selector(get1)] && [n respondsTo:@selector(get2)])
    return [self set:value-[n get1]:[n2 get]-[n get2]];
  else if ([n respondsToSelector:@selector(get)])
    return [self set:value-[n get]:[n2 get]-[n get]];
  else {
    printf("!!! odčítání nepoužitelného objektu !!!\n");
    return self;
  }
}
... jako v příkladu 3 ...
@end
// end of file

Podívejme se podrobněji na jednotlivé části programu:

1. Standardní zprávy isKindOfClass a class — sample4.m

V nové implementaci metody add: nejprve ověříme je-li objekt n objektem třídy ModMN (nebo kteréhokoli z jejích případných dědiců). K tomu slouží standardní zpráva isKindOfClass:. Parametrem zprávy je identifikace třídy, kterou zjistíme tak, že třídě pošleme další standardní zprávu — zprávu class.

Implementace nejprve zjistí jedná-li se o objekt třídy (alespoň) ModMN a jestliže ano, přičte jej standardním způsobem. Pak ještě ověříme, zda se nejedná o objekt třídy ModN (nebo některého z jejích případných dědiců odlišných od třídy ModMN); ano-li, můžeme jej přičíst s využitím zprávy get. Jinak ohlásíme chybu; program však pořád pracuje dál a nezhroutí se — na rozdíl od C++.

2. Standardní zpráva respondsToSelector a operátor @selector — sample4.m

Pro implementaci zprávy sub: využijeme jiný mechanismus: optáme se objektu přímo je-li schopen zpracovat určenou zprávu (o něčem podobném se už C++ nezdá vůbec). K tomu slouží standardní zpráva respondsToSelector:; jejím parametrem je identifikace požadované zprávy získaná pomocí standardního operátoru @selector.

Implementace metody sub: tedy nejprve ověří, je-li zadaný objekt schopen zpracovat zprávy get1 a get2; ano-li, přičte číslo standardním způsobem. Ne-li, zjistíme, zná-li objekt alespoň zprávu get, abychom jej mohli přičíst jako objekt třídy ModN; jinak ohlásíme chybu.

Uvědomme si, že toto druhé řešení je ještě mnohem flexibilnější — tentokrát můžeme pracovat s objekty libovolné třídy, jestliže jsou schopny zpracovat odpovídající zprávy. Nejsme tedy omezeni pouze na objekty třídy ModMN a jejích dědiců; zpráva sub: korektně odečte například objekt reprezentující číselnou řadu, bude-li tento objekt schopen zareagovat na zprávu get třeba vypočtením limity.


Zpět Obsah Další

Copyright © Chip, O. Čada 2000-2003