2010-01-20 23 views
26

Estoy tratando de crear una fábrica (patrón de diseño) en Objective C Así que estoy haciendo algo como:fábrica (patrón de diseño) en 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{ 
    // ... 
} 

Sin embargo, yo no quiero que el createBlueCar y el createRedCar para estar disponible para el público y, si no los defino en el archivo .h, recibo una advertencia de la definición faltante.

Soy un antiguo desarrollador de Java y un novato en Objective-C. Por lo que podría ser una mala práctica. De ser así, qué buena práctica es hacerlo.

+2

Normalmente no tiene clases de fábrica en Objective-C ya que las clases son objetos de primera clase. Mire las clases de paraguas tales como NSPredicate o NSNumber. Son fábricas. Por lo general, obtendrá una subclase de NSPredicate o NSNumber devuelta. –

+2

De acuerdo con @AdamSmith, la mejor manera de hacerlo sería un método de clase en automóvil, p. Ej. '+ (Car *) carWithColor: (int) color;' – dmur

+0

De hecho, noté otra cosa que podría no estar clara al venir de Java. Si "createCar" está en la clase de CarFactory, la mejor práctica es escribir [self createBlueCar]. En ObjC las clases son objetos a diferencia de Java. Entonces self en un método de clase se refiere al objeto de clase (CarFactory en este caso).La razón para usar "self" es que el código no se romperá si hereda "CarFactory" y vuelve a implementar, p. "createBlueCar" –

Respuesta

49

La mejor manera de hacerlo es con una extensión de clase.

.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 

Una extensión de clase es una solución mejor porque es una verdadera extensión de la interfaz de la clase mientras que una categoría (sin un correspondiente implementación) es meramente una sugerencia de que la clase implemente los métodos. Es decir, el compilador advertirá si no implementa la interfaz (los métodos) declarada en la extensión de clase, pero no advertirá si usted hizo lo mismo con una categoría con nombre.

Tenga en cuenta también que una extensión de clase le permite actualizar una propiedad readonly a una propiedad readwrite según el ejemplo anterior.

+2

+1 Esta debería ser realmente la respuesta aceptada, ya que demuestra cómo hacerlo y por qué. –

4

Creo que puede agregarlos a la clase utilizando un archivo objective-c category dentro de la implementación (no la interfaz) como una forma de emular los métodos privados si desea "ocultarlos" a los usuarios de su clase.

Tenga en cuenta que, aunque ya no publicitará los métodos a los clientes de su clase, aún podrán usarlos si usan los selectores correctos. Además, siempre pueden usar algo como classdump para regenerar la interfaz completa de tu clase para que tus métodos nunca se oculten realmente.

Consulte this question para obtener más ejemplos de cómo crear métodos "privados" en Object-C.

+0

pero luego tendré el "hide" del archivo h que contiene la categoría –

+2

@Guy: no, puede implementar la categoría completamente en el archivo de implementación. No hay nada que decir que una sección @interface debe estar en un archivo .h. – jkp

+1

@Guy JKP tiene razón, lo pones en la parte superior del .m, es una práctica bastante común. Recuerde: nunca hay nada privado en Objectivo-c, solo invisible o desconocido. – slf

-1

Se puede crear una función privada estática

@implementation Car 

static createBlueCar() { 
    .... 
} 

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

@end 

pero no, no se puede crear un verdadero miembro privado . (Puede invocar algunas convenciones, por ejemplo, +(Car*)private_createCar en una categoría privada para desalentar su uso.)

Cuestiones relacionadas