2011-12-28 8 views
9

Nel secondo capitolo del suo libro di programmazione iOS, Joe Conway descrive l'uso di "sé" nei metodi di classe in caso di sottoclassi. Comprendo questo concetto e ho una domanda sul problema della sottoclasse.Come sovrascrivere correttamente un metodo di classe in un Objective-C in una sottoclasse?

Background: Abbiamo creato una classe Possesso cui metodo di classe + randomPossession si presenta così:

+(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]; 
} 

Sono consapevole del fatto che il valore di ritorno in realtà dovrebbe essere di tipo id tale che id = newPossession ...

I sottoclasse Possesso e ha creato una classe chiamata BallGlove che ha incluso un nuovo iVar, Marca, un NSString *

ho calpestato il + randomPossession in BallGlove come segue:

+(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; 
} 

La mia domanda è questa: è il modo in cui ho scavalcato questo metodo di classe appropriato e accettabile dalla comunità (ad es. parallelo il formato -init catturando la super implementazione in una variabile, manipolare la variabile di conseguenza e quindi restituirla? Il mio output mostra che l'oggetto restituito è un'istanza di BallGlove, tuttavia, ero interessato all'implementazione accettabile. Grazie in anticipo.

risposta

0

È tecnicamente ok.

Proporrei un'alternativa, comunque. Se hai già un inizializzatore pubblico designato sulla tua classe base (che potresti voler creare e chiamare comunque da quel metodo di classe factory), e poi usare quel inizializzatore (o anche uno nuovo della sottoclasse) nella classe delle sottoclassi metodo.

Non è molto più codice, ma secondo me è più facile da seguire e a prova di futuro. L'inizializzatore potrebbe tornare utile a un certo punto, ma ovviamente non è una soluzione per ogni applicazione.

+0

+ randomPossession nella classe base in effetti chiama l'inizializzatore designato. Il metodo di classe crea anche valori "casuali" per quell'inizializzatore. Se faccio ciò che ritengo suggerisco, dovrei replicare il codice per quei valori "casuali" nel metodo della classe sovrascritta (+ randomPossession), oltre a sovrascrivere l'inizializzatore designato per chiamare un nuovo inizializzatore della classe BallGlove, che sarebbe aggiungi le mie ulteriori informazioni su iVar. Perché sovrascrivere il metodo di classe come ho proposto di essere dannoso in senso generale? Non può essere paragonato a concatenare gli inizializzatori? –

+0

Non penso che sia eccessivamente brutto, ma non è un modello molto comune. La domanda in sé è un buon indicatore per questo. :) Una cosa che diventa un po 'vaga con la sottoclasse è il nome del metodo, e una buona nomenclatura è una delle cose migliori dell'obiettivo-c. Quindi nel tuo caso un metodo + randomBallGlove potrebbe essere meglio che ignorare. – Eiko

+0

Stai suggerendo di creare invece un metodo di classe denominato + randomBallGlove che include l'implementazione di + randomPossession oltre all'implementazione personalizzata desiderata? Per me va bene. Cosa suggerisci che + randomPossession sia ancora disponibile per sottoclassi di Possession? sovrascrivere il metodo e lanciare un'eccezione che indichi l'uso di + randomBallGlove? Questo è in genere il normale protocollo di tali eventi?So che questo esempio potrebbe non esistere nella realtà, sto solo imparando e sono curioso di accettare l'implementazione nel caso in cui ciò accada. Grazie per l'aiuto! –

1

Sì, è accettabile eseguire l'inizializzazione in questo modo. In effetti è così che viene fatto nella maggior parte dei casi. Voglio dire, questa è la ragione per ereditare da una super classe in primo luogo. Vuoi roba in aggiunta a ciò che è presente nella super classe. Quindi, inserisci il codice in qualsiasi cosa sia specifica per la classe ereditata e dovrebbe essere fatto in questo modo.

Penso che il modo in cui si desidera che l'oggetto BallGlove inizializzato sia anche un fattore nel modo in cui si definisce il metodo ereditato. La domanda si pone chiamando l'init Possession o chiamando il init BallGlove (Non che la creazione di un'istanza di una classe è l'unico posto per utilizzare un metodo di classe). Quindi si tratta della logica della creazione dei tuoi oggetti, cioè come stai descrivendo l'oggetto BallGlove: stai facendo in modo che il tuo metodo di classe lo descriva in modo da adattarlo ai criteri dell'oggetto BallGlove e non diventi oggetto generico Possession. La mia risposta è che se è possibile implementarlo correttamente, è accettabile utilizzare una linea parallela di metodi di classe.

Inoltre, non importa se si sta tornando di tipo Possession nella classe super-perché, id può puntare a un oggetto di qualsiasi tipo di classe

+0

Grazie per la risposta. Ciò non ha comunque risposto alla domanda. La domanda riguardava il formato dei metodi di classe che sovrascrivevano. A parte la necessità di generare un metodo di convenienza per una sottoclasse, non sono sicuro di avere un motivo per sovrascrivere il metodo di classe. Come tale, non ho ancora visto nulla su questo. Ci sono esempi che dimostrino che il formato che ho usato sia appropriato? –

+0

@BrianPalma Mi dispiace. Forse non ho risposto bene. Non vedo davvero perché non sia accettabile farlo per i metodi di classe allo stesso modo degli inizializzatori. Il modo in cui funziona è che i metodi di classe tendono a chiamare i metodi init, eseguono del codice e restituiscono una versione autorelitta che è ciò che stai facendo. Non so se ci sono esempi per verificare il tuo formato, ma non riesco nemmeno a vedere alcun problema che possa sorgere da esso. Fammi controllare alcuni codici di esempio e tornare da te. – MadhavanRP

2

Sì, questo è un modo perfettamente sensato per farlo. Non c'è nulla di particolarmente diverso tra i metodi di classe e i metodi normali: solo quello viene eseguito da una classe e l'altro viene eseguito da un'istanza.

2

Nel momento in cui si esegue l'override di un metodo di classe, è possibile decidere di implementarlo con l'aiuto della super implementazione o senza di esso. Dipende totalmente da te. Overiding init è una storia completamente diversa, non solo perché è un metodo di istanza, ma perché ha una convenzione/contratto ad esso associati. Tieni presente che, per esempio, i principi del sottotitolo di Liskov non dovrebbero essere violati.

L'override del metodo di classe è perfettamente soddisfacente, anche se prenderei in considerazione l'idea di dare un tocco di classe ai metodi di classe. Sebbene sia molto ben possibile in Objective-C, non è in altre lingue e questo per una buona ragione. Il concetto di polimorfismo come concetto è meglio legato a esempi che possono essere usati come sostituti l'uno dell'altro, mentre l'uso di metodi di classe spezza il concetto (cioè non una vera sottotitolazione).È intelligente, ma non necessariamente intuitivo e flessibile.

+0

Grazie per la risposta. Come ho accennato di seguito, non sono a conoscenza di alcun uso di override di un particolare metodo di classe in una sottoclasse, tranne che per meno codice in un metodo di convenienza. A questo punto, non ho intenzione di farlo. Ero semplicemente curioso riguardo alla corretta implementazione se la situazione si presentasse. –

+0

@BrianPalma: esistono motivi per sostituire i metodi di classe diversi dai "metodi di convenienza". Ad esempio, i metodi di classe 'defaultMenu' e' requiresConstraintBasedLayout' di NSView esistono solo per essere sovrascritti. – Chuck

+0

@Chuck Scusa, penso di aver misspoke o sono semplicemente troppo nuovo! Intendo i "metodi di convenienza" in termini di oggetti del modello. Capisco che ci sono metodi di classe in iOS e OS X che esistono puramente per essere sovrascritti e richiedono [super someClassMethodHere]; –

Problemi correlati