2011-12-28 9 views
9

En el segundo capítulo de su libro de programación de iOS, Joe Conway describe el uso de 'self' en métodos de clase en el caso de subclases. Entiendo este concepto y tengo una pregunta sobre el tema de la creación de subclases.¿Cómo anulo correctamente un método de clase en un Objective-C en una subclase?

Antecedentes: Hemos creado una clase cuya posesión método de clase + randomPossession se ve así:

+(id)randomPossession 
{ 
NSArray *randomAdjectiveList = [NSArray arrayWithObjects:@"Fluffy", @"Rusty", @"Shiny", nil]; 
NSArray *randomNounList = [NSArray arrayWithObjects:@"Bear", @"Spork", @"Mac", nil]; 

unsigned long adjectiveIndex = rand() % [randomAdjectiveList count]; 
unsigned long nounIndex = rand() % [randomNounList count]; 

NSString *randomName = [NSString stringWithFormat:@"%@ %@", [randomAdjectiveList objectAtIndex:adjectiveIndex], [randomNounList objectAtIndex:nounIndex]]; 

int randomValue = rand() % 100; 

NSString *randomSerialNumber = [NSString stringWithFormat:@"%c%c%c%c%c", 
           '0' + rand() % 10, 
           'A' + rand() % 10, 
           '0' + rand() % 10, 
           'A' + rand() % 10, 
           '0' + rand() % 10]; 

Possession *newPossession = [[self alloc] initWithPossessionName:randomName valueInDollars:randomValue serialNumber:randomSerialNumber]; 

return [newPossession autorelease]; 
} 

Soy consciente de que el valor de retorno debe realmente ser de tipo ID Identificación de tal manera que newPossession = ...

I subclases posesión y creó una clase llamada BallGlove que incluía un nuevo Ivar, nombre de la marca, un NSString *

me hizo caso omiso de la randomPossession + en BallGlove de la siguiente manera:

+(id)randomPossession 
{ 
BallGlove *myGlove = [super randomPossession]; 

NSArray *brandNames = [NSArray arrayWithObjects:@"Rawlings", @"Mizuno", @"Wilson", nil]; 

unsigned long randomNameIndex = rand() % [brandNames count]; 

[myGlove setBrandName:[brandNames objectAtIndex:randomNameIndex]]; 

NSLog(@"myGlove is of type class: %@", [self class]); 

return myGlove; 
} 

Mi pregunta es esta: ¿Es la manera en que superé este método de clase apropiado y aceptable por la comunidad (es decir Paralelamente al formato de entrada capturando la súper implementación en una variable, manipule la variable en consecuencia y luego devuélvala. Mi resultado muestra que el objeto devuelto es una instancia de BallGlove; sin embargo, estaba interesado en la implementación aceptable. Gracias por adelantado.

Respuesta

0

Está técnicamente bien.

Propongo una alternativa, sin embargo. Si ya tiene un inicializador público designado en su clase base (que puede querer crear y llamar desde ese método de clase de fábrica de todos modos), y luego use ese mismo inicializador (o incluso uno nuevo de su subclase) en la clase de sus subclases método.

No es mucho más código, pero en mi opinión más fácil de seguir y a prueba de futuro. El inicializador también puede ser útil en un punto, pero por supuesto no es una solución para cada aplicación.

+0

+ randomPossession en la clase base de hecho llama al inicializador designado. El método de clase también crea valores "aleatorios" para ese inicializador. Si hago lo que creo que estás sugiriendo, tendría que replicar el código para esos valores "aleatorios" en el método de clase reemplazado (+ randomPossession) así como anular el inicializador designado para llamar a un nuevo inicializador de la clase BallGlove, que haría agregue mi información iVar adicional. ¿Por qué está anulando el método de clase como lo propuse perjudicial en un sentido general? ¿No se puede comparar con encadenar inicializadores? –

+0

No creo que sea demasiado feo, simplemente no es un patrón muy común. La pregunta en sí es un buen indicador de eso. :) Una cosa que se vuelve un poco vaga con la subclasificación es el nombre del método, y un buen nombre es una de las mejores cosas sobre objetivo-c. Entonces, en tu caso, un método + random BallGlove podría ser mejor que anular. – Eiko

+0

¿Está sugiriendo que, en su lugar, cree un método de clase llamado + random BallGlove que incluya la implementación de + randomPossession además de la implementación personalizada deseada? Suena bien para mí. ¿Qué sugieres para que + la Posesión aleatoria siga estando disponible para las subclases de Posesión? anular el método y hacer que arroje una excepción al dirigir el uso de + randomBallGlove? ¿Es este el protocolo normal de tales eventos?Sé que este ejemplo puede no existir en realidad, solo estoy aprendiendo y tengo curiosidad por la implementación aceptada en caso de que suceda. ¡Gracias por tu ayuda! –

1

Sí, es aceptable hacer su inicialización así. De hecho, así es como se hace en la mayoría de los casos. Quiero decir, esa es la razón para heredar de una súper clase en primer lugar. Desea cosas además de lo que está presente en la súper clase. Entonces, inserta código en lo que sea específico de la clase heredada y debería hacerse de esa manera.

Creo que la forma en que desea que se inicialice el objeto BallGlove también es un factor en cómo define su método heredado. La pregunta surge al llamar al Possession init o al llamar al BallGlove init (No es que la creación de una instancia de una clase sea el único lugar para usar un método de clase). Entonces, todo se reduce a la lógica de crear objetos, es decir, cómo describes bien el objeto BallGlove: ¿estás asegurándote de que tu método de clase lo describe de manera que se ajuste al criterio de objeto BallGlove y no se convierta en el objeto genérico Possession? Mi respuesta es que si puedes implementarlo correctamente, usar una línea paralela de métodos de clase es aceptable.

Además, no importa si usted está volviendo de tipo Possession en su superclase porque, id puede apuntar a un objeto de cualquier tipo de clase

+0

Gracias por la respuesta. Sin embargo, eso realmente no respondió la pregunta. La pregunta se refería al formato de los métodos de clase superiores. Además de la necesidad de generar un método de conveniencia para una subclase, no estoy seguro de una razón para anular el método de clase. Como es tal, no he visto nada sobre esto todavía. ¿Hay algún ejemplo que verifique que el formato que utilicé sea apropiado? –

+0

@BrianPalma Lo siento. Tal vez no respondí bien. Realmente no veo por qué no es aceptable hacerlo para los métodos de clase de la misma manera que los inicializadores. La forma en que me imagino que funciona es que los métodos de clase tienden a llamar a los métodos de init, realizar algún código y devolver una versión de autorretrato, que es lo que estás haciendo. No sé si hay ejemplos para verificar su formato, pero tampoco veo ningún problema que pueda surgir. Déjame revisar algunos códigos de muestra y contactarte. – MadhavanRP

2

Sí, eso es una manera perfectamente sensata para hacerlo. No hay nada particularmente diferente entre los métodos de clase y los métodos normales: solo uno lo realiza una clase y el otro lo realiza una instancia.

2

En el momento en que anula un método de clase, puede decidir implementarlo con la ayuda de la implementación súper o sin él. Depende totalmente de usted. Overiding init es una historia completamente diferente, no solo porque es un método de instancia sino porque tiene una convención/contrato asociado. Tenga en cuenta que, por ejemplo, no se debe violar el principio de la Substitución de Liskov.

Su sobreescrito del método de la clase está perfectamente bien, aunque consideraría superar los métodos de la clase como un olor de diseño. Aunque es muy posible en Objective-C, no está en otros idiomas y eso por una muy buena razón. El polimorfismo como concepto está mejor ligado a instancias que pueden usarse como sustitutos entre sí, mientras que el uso de métodos de clase rompe el concepto (es decir, no hay una sustitución real).Es inteligente, pero no necesariamente necesario, intuitivo y flexible.

+0

Gracias por la respuesta. Como mencioné a continuación, no estoy al tanto de ningún uso de sobreescribir un método de clase en particular en una subclase, a menos que sea por menos código en un método de conveniencia. En este punto, no tengo intención de hacerlo. Simplemente tenía curiosidad sobre la implementación adecuada si surgiera la situación. –

+0

@BrianPalma: hay razones para anular los métodos de clase que no sean "métodos de conveniencia". Por ejemplo, los métodos de clase 'defaultMenu' y' requiresConstraintBasedLayout' de NSView existen para ser anulados. – Chuck

+0

@Chuck Lo siento, creo que me equivoqué o soy demasiado nuevo. Me refiero a "métodos de conveniencia" en términos de objetos modelo. Entiendo que hay métodos de clase en iOS y OS X que existen para ser anulados y requieren [super someClassMethodHere]; –

Cuestiones relacionadas