2010-01-20 1 views
26

Sto cercando di creare una fabbrica (design pattern) in Objective C Così sto facendo qualcosa di simile:Factory (design pattern) in Objective C

+ (Car *)createCar:(int)color { 
    if (color == 1) { 
     return [CarFactory createBlueCar]; 
    } else if (color == 2) { 
     return [CarFactory createRedCar]; 
    } else { 
     return nil; 
    } 
} 

+ (Car *)createBlueCar { 
    // ... 
} 

+(Car*)createRedCar{ 
    // ... 
} 

Comunque io non voglio che il createBlueCar e lo createRedCar deve essere disponibile al pubblico e se non li definisco nel file .h, viene visualizzato un avviso relativo alla definizione mancante.

Sono un ex sviluppatore Java e un novizio in Objective-C - Quindi potrebbe essere solo una cattiva pratica Se è così, quale sia la buona pratica di farlo.

+2

Di solito non si hanno classi Factory in Objective-C poiché le classi sono oggetti di prima classe. Guarda le classi Umbrella come NSPredicate o NSNumber. Sono fabbriche. Solitamente verrà restituita una sottoclasse di NSPredicate o NSNumber. –

+2

Accetto con @AdamSmith, il modo migliore per farlo sarebbe un metodo di classe su Car, ad es. '+ (Car *) carWithColor: (int) color;' – dmur

+0

In realtà ho notato un'altra cosa che potrebbe non essere chiara quando si proviene da Java. Se "createCar" è sulla classe CarFactory, la migliore pratica è di solito scrivere [self createBlueCar]. Nelle classi ObjC ci sono oggetti diversi da Java. Quindi self in un metodo di classe si riferisce all'oggetto di classe (CarFactory in questo caso).Il motivo dell'uso di "self" è che il codice non si interrompe se si eredita "CarFactory" e si reimplementa ad es. "createBlueCar" –

risposta

49

Il modo migliore per farlo è con un'estensione di classe.

.h

@interface MyClass : NSObject 
@property(readonly) BOOL publiclyReadOnlyPrivatelyWritableFlag; 
+ (id) myExposedFactoryMethod; 
@end 

.m

#import "MyClass.h" 

@interface MyClass() 
@property(readwrite) BOOL publiclyReadOnlyPrivatelyWritableFlag; 
+ (id) privateMethod1; 
+ (id) privateMEthod2; 
@end 

@implementation MyClass 
@synthesize publiclyReadOnlyPrivatelyWritableFlag; // no ivar -- only works in 64 bit and iPhone 
+ (id) myExposedFactoryMethod 
{ 
    ... 
    [self privateMethod1]; 
    ... 
} 

+ (id) privateMethod1; 
{ 
    return ... 
} 

+ (id) privateMEthod2; 
{ 
    return ... 
} 
@end 

Un'estensione classe è una soluzione migliore perché è un vero estensione dell'interfaccia della classe che una categoria (senza un corrispondente implementazione) è semplicemente un suggerimento che la classe implementa i metodi. Cioè, il compilatore avviserà se non si implementa l'interfaccia - i metodi - dichiarati nell'estensione di classe, ma non avviserà se si è fatto lo stesso con una categoria nominata.

Si noti inoltre che un'estensione di classe consente di aggiornare una proprietà readonly a una proprietà readwrite come nell'esempio precedente.

+2

+1 Questa dovrebbe essere la risposta accettata, poiché dimostra come farlo e precisamente perché. –

4

Penso che sia possibile aggiungerli alla classe utilizzando un objective-c category all'interno del file di implementazione (non dell'interfaccia) come metodo di emulazione dei metodi privati ​​se si desidera "nasconderli" dagli utenti della classe.

Nota, anche se non si pubblicizzano più i metodi per i client della classe, saranno comunque in grado di utilizzarli se utilizzano i selettori corretti. Inoltre, possono sempre utilizzare qualcosa come classdump per rigenerare l'interfaccia completa alla classe in modo che i tuoi metodi non vengano mai nascosti veramente.

Vedere this question per ulteriori esempi di creazione di metodi "privati" sotto l'obiettivo-c.

+0

ma poi avrò il "nascondi" del file h contenente la categoria –

+2

@Guy: no, è possibile implementare completamente la categoria all'interno del file di implementazione. Non c'è niente da dire che una sezione @interface deve essere in un file .h. – jkp

+1

@Guy JKP ha ragione, lo metti nella parte superiore del .m, è una pratica abbastanza normale. Ricorda: non c'è mai nulla di privato in obiettivo-c, solo invisibile o sconosciuto – slf

-1

è possibile creare un privato statica funzione

@implementation Car 

static createBlueCar() { 
    .... 
} 

+(Car*) createCar:(int) color{ 
    if (color==1) { 
    return createBlueCar(); 
    } ... 
} 

@end 

, ma no, non è possibile creare un vero e proprio privato membro. (Puoi invocare alcune convenzioni, ad esempio +(Car*)private_createCar in una categoria privata per scoraggiarne l'uso.)