2010-01-20 8 views
26

Je suis en train de créer une usine (design pattern) dans l'objectif C Je fais quelque chose comme:Usine (design pattern) dans l'objectif 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{ 
    // ... 
} 

Cependant, je ne veux pas le createBlueCar et le createRedCar pour être disponible au public et si je ne les définis pas dans le fichier .h alors j'obtiens un avertissement de la définition manquante. Je suis un ancien développeur Java et un débutant en Objective-C - Donc ce n'est peut-être qu'une mauvaise pratique Si oui, quelle est la bonne pratique de le faire.

+2

Vous n'avez généralement pas de classes Factory en Objective-C car les classes sont des objets de première classe. Regardez les classes Umbrella telles que NSPredicate ou NSNumber. Ce sont des usines. Vous obtiendrez généralement une sous-classe de NSPredicate ou NSNumber retourné. –

+2

D'accord avec @AdamSmith, la meilleure façon de le faire serait une méthode de classe sur Car, par ex. '+ (Car *) carWithColor: (int) color;' – dmur

+0

En fait, j'ai remarqué une autre chose qui pourrait ne pas être claire en venant de Java. Si "createCar" est sur CarFactory, la meilleure pratique consiste à écrire [self createBlueCar]. Dans les classes ObjC, les objets sont différents de Java. Ainsi, self dans une méthode de classe fait référence à l'objet de classe (CarFactory dans ce cas).La raison pour laquelle vous utilisez "self" est que le code ne se casse pas si vous héritez de "CarFactory" et réimplémentez par exemple. "createBlueCar" –

Répondre

49

La meilleure façon d'y parvenir est d'utiliser une extension de 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 

Une extension de classe est une meilleure solution, car il est une véritable extension de l'interface de la classe alors qu'une catégorie (sans correspondant implémentation) est simplement une suggestion que la classe implémente les méthodes. Autrement dit, le compilateur vous avertira si vous n'implémentez pas l'interface - les méthodes - déclarées dans l'extension de classe, mais ne vous avertira pas si vous avez fait de même avec une catégorie nommée.

Notez également qu'une extension de classe vous permet de mettre à niveau une propriété readonly vers une propriété readwrite conformément à l'exemple ci-dessus.

+2

+1 Cela devrait vraiment être la réponse acceptée, car elle montre comment le faire et précisément pourquoi. –

4

Je pense que vous pouvez les ajouter à la classe en utilisant un objective-c category dans le fichier d'implémentation (pas l'interface) comme moyen d'émuler des méthodes privées si vous voulez les "cacher" aux utilisateurs de votre classe.

Notez, bien que vous n'annuerez plus les méthodes aux clients de votre classe, ils pourront toujours les utiliser s'ils utilisent les bons sélecteurs. De plus, ils peuvent toujours utiliser quelque chose comme classdump pour régénérer l'interface complète de votre classe afin que vos méthodes ne soient jamais vraiment cachées.

Voir this question pour d'autres exemples de création de méthodes "privées" dans l'objectif-c.

+0

mais alors je vais avoir le "cacher" le fichier h contenant la catégorie –

+2

@Guy: non, vous pouvez implémenter la catégorie entièrement dans le fichier d'implémentation. Il n'y a rien à dire qu'une section @interface doit être dans un fichier .h. – jkp

+1

@Guy JKP a raison, vous le mettez en haut du .m, c'est une pratique assez courante. Rappelez-vous: il n'y a jamais rien de privé dans l'objectif-c, seulement invisible ou inconnu – slf

-1

Vous pouvez créer une fonction statique privée

@implementation Car 

static createBlueCar() { 
    .... 
} 

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

@end 

mais non, vous ne pouvez pas créer un véritable privé. (Vous pouvez appeler certaines conventions, par exemple, +(Car*)private_createCar dans une catégorie privée pour en décourager l'utilisation.)

Questions connexes