Oggetti compositi Objective-C

Possiamo creare una sottoclasse all'interno di un cluster di classi che definisce una classe che incorpora al suo interno un oggetto. Questi oggetti di classe sono oggetti compositi. Quindi ti starai chiedendo cos'è un cluster di classi. Quindi vedremo prima cos'è un cluster di classi.

Cluster di classe

I cluster di classi sono un modello di progettazione di cui il framework di base fa ampio uso. I cluster di classi raggruppano una serie di sottoclassi concrete private in una superclasse astratta pubblica. Il raggruppamento delle classi in questo modo semplifica l'architettura pubblicamente visibile di un framework orientato agli oggetti senza ridurne la ricchezza funzionale. I cluster di classi si basano suabstract factory design pattern.

Per renderlo semplice, invece di creare più classi per funzioni simili, creiamo un'unica classe che si prenderà cura della sua gestione in base al valore di input.

Ad esempio, in NSNumber abbiamo molti cluster di classi come char, int, bool e così via. Li raggruppiamo tutti in una singola classe che si occupa di gestire le operazioni simili in una singola classe. NSNumber racchiude effettivamente il valore di questi tipi primitivi in ​​oggetti.

Cos'è un oggetto composito?

Incorporando un oggetto cluster privato in un oggetto di nostra progettazione, creiamo un oggetto composito. Questo oggetto composito può fare affidamento sull'oggetto cluster per le sue funzionalità di base, intercettando solo i messaggi che l'oggetto composito desidera gestire in un modo particolare. Questa architettura riduce la quantità di codice che dobbiamo scrivere e consente di sfruttare il codice testato fornito da Foundation Framework.

Ciò è spiegato nella figura seguente.

L'oggetto composto deve dichiararsi una sottoclasse della superclasse astratta del cluster. Come sottoclasse, deve sovrascrivere i metodi primitivi della superclasse. Può anche sovrascrivere i metodi derivati, ma questo non è necessario perché i metodi derivati ​​funzionano attraverso quelli primitivi.

Il metodo count della classe NSArray è un esempio; l'implementazione dell'oggetto intermedio di un metodo che sovrascrive può essere semplice come:

- (unsigned)count  {
   return [embeddedObject count];
}

Nell'esempio precedente, l'oggetto incorporato è in realtà di tipo NSArray.

Un esempio di oggetto composito

Ora per vedere un esempio completo, diamo un'occhiata all'esempio dalla documentazione Apple che viene fornita di seguito.

#import <Foundation/Foundation.h>

@interface ValidatingArray : NSMutableArray {
   NSMutableArray *embeddedArray;
}

+ validatingArray;
- init;
- (unsigned)count;
- objectAtIndex:(unsigned)index;
- (void)addObject:object;
- (void)replaceObjectAtIndex:(unsigned)index withObject:object;
- (void)removeLastObject;
- (void)insertObject:object atIndex:(unsigned)index;
- (void)removeObjectAtIndex:(unsigned)index;

@end

@implementation ValidatingArray
- init {
   self = [super init];
   if (self) {
      embeddedArray = [[NSMutableArray allocWithZone:[self zone]] init];
   }
   return self;
}

+ validatingArray {
   return [[self alloc] init] ;
}

- (unsigned)count {
   return [embeddedArray count];
}

- objectAtIndex:(unsigned)index {
   return [embeddedArray objectAtIndex:index];
}

- (void)addObject:(id)object {
   if (object != nil) {
      [embeddedArray addObject:object];
   }
}

- (void)replaceObjectAtIndex:(unsigned)index withObject:(id)object; {
   if (index <[embeddedArray count] && object != nil) {
      [embeddedArray replaceObjectAtIndex:index withObject:object];
   }
}

- (void)removeLastObject; {
   if ([embeddedArray count] > 0) {
      [embeddedArray removeLastObject];
   }
}

- (void)insertObject:(id)object atIndex:(unsigned)index; {
   if (object != nil) {
      [embeddedArray insertObject:object atIndex:index];
   }
}

- (void)removeObjectAtIndex:(unsigned)index; {
   if (index <[embeddedArray count]) {
      [embeddedArray removeObjectAtIndex:index];
   }
}

@end

int main() {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
   ValidatingArray *validatingArray = [ValidatingArray validatingArray];
   
   [validatingArray addObject:@"Object1"];
   [validatingArray addObject:@"Object2"];
   [validatingArray addObject:[NSNull null]];
   [validatingArray removeObjectAtIndex:2];
   NSString *aString = [validatingArray objectAtIndex:1];
   NSLog(@"The value at Index 1 is %@",aString);
   [pool drain];
   
   return 0;
}

Ora, quando compiliamo ed eseguiamo il programma, otterremo il seguente risultato.

2013-09-28 22:03:54.294 demo[6247] The value at Index 1 is Object2

Nell'esempio sopra, possiamo vedere che la convalida dell'unica funzione dell'array non consentirebbe l'aggiunta di oggetti nulli che porteranno al crash nello scenario normale. Ma il nostro array di convalida se ne occupa. Allo stesso modo, ogni metodo di convalida dell'array aggiunge processi di convalida oltre alla normale sequenza di operazioni.