Domanda

In Ruby, c'è moduli e si può estendere una classe da "mixing-in" del modulo.

module MyModule
  def printone
    print "one" 
  end
end

class MyClass
  include MyModule
end

theOne = MyClass.new
theOne.printone 
>> one

In Objective-C, trovo che ho una serie di metodi comuni che voglio una serie di classe a "ereditare". In quali altri modi posso realizzare questo senza creare una classe comune e derivanti tutti da quella classe comune?

È stato utile?

Soluzione

Modifica :. Cambiamenti aggiunti perché alcune persone si sentono sono responsabile per le limitazioni di Objective-C

Risposta breve : non si può. Objective-C non ha l'equivalente di mixins Ruby.

risposta Leggermente meno breve : Objective-C ha qualcosa con probabilmente lo stesso sapore: protocolli. Protocolli (interfacce in alcune altre lingue), sono un modo per definire una serie di metodi di una classe che adotta i protocolli che si impegnano a implementare. Un protocollo non fornisce un'implementazione però. Tale limitazione impedisce utilizzando protocolli come equivalente esatto mixins rubino.

risposta ancora meno breve: Tuttavia, il runtime Objective-C ha un'API esposto che ti permette di giocare con le caratteristiche dinamiche del linguaggio. Poi passo al di fuori la lingua, ma si può avere protocolli con implementazioni di default (chiamato anche protocolli di cemento). La risposta di Vladimir mostra un modo per farlo. A quel punto mi sembra che si ottiene mixins Rubino bene.

Tuttavia, non sono sicuro mi sento di raccomandare a farlo. Nella maggior parte dei casi, altri modelli misura la fattura, senza giocare con il runtime. Ad esempio, si può avere un sub-oggetto che implementa il metodo misto-in ( ha-un al posto di è-un ). Giocando con il runtime è OK, ma ha 2 svantaggi:

  • rendere il codice meno leggibile in quanto richiede ai lettori di sapere molto di più che la lingua. Certo si può (e si deve) commentarlo, ma ricordate che ogni commento necessaria può essere visto come un difetto di implementazione.

  • È dipendete che implementazione del linguaggio. Certo, le piattaforme Apple sono di gran lunga i più comuni per Objective-C, ma non dimenticate Cocotron o GNUstep (o Etoilé) che hanno differenti tempi di esecuzione, che possono o non possono essere compatibili con Apple in questo senso.

Come nota a margine, premetto di seguito che le categorie non possono aggiungere stato (variabili di istanza) per una classe. Utilizzando l'API runtime, è possibile sollevare questa limitazione troppo. Questo è oltre la portata di questa risposta però.

Risposta lunga:

Due caratteristiche Objective-C sembrano possibili candidati: categorie e protocolli. Le categorie non sono davvero la scelta giusta qui, se ho capito la domanda in modo corretto. La funzione di destra è un protocollo.

Vi faccio un esempio. Si supponga di voler un mucchio delle classi di avere una capacità specifica denominata "cantare". Poi si definisce un protocollo:

@protocol Singer
    - (void) sing;
@end

Ora si può dichiarare che le tue proprie classi adotta il protocollo seguente modo:

@interface Rectangle : Shape <Singer> {
    <snip>
@end

@interface Car : Vehicle <Singer> {
    <snip>
@end

dichiarando che essi adottano il protocollo si impegnano ad attuare il metodo sing. Ad esempio:

@implementation Rectangle

- (void) sing {
    [self flashInBrightColors];
}

@end

@implementation Car

- (void) sing {
    [self honk];
}

@end

Quindi si utilizza queste classi per esempio come questo:

void choral(NSArray *choir) // the choir holds any kind of singer
{
    id<Singer> aSinger;
    for (aSinger in choir) {
        [aSinger sing];
    }
}

Si noti che i cantanti nella matrice non hanno bisogno di avere una superclasse comune. Si noti inoltre che una classe può avere un solo superclasse, ma molti protocolli adottati. Avviso, infine, che tipo di controllo viene effettuato dal compilatore.

In effetti, il meccanismo di protocollo è ereditarietà multipla utilizzato per il pattern mixin. Che l'ereditarietà multipla è fortemente limitata a causa di un protocollo non può aggiungere nuove variabili di istanza di una classe. Un protocollo descrive solo un'interfaccia pubblica adottanti devono implementare. Diversamente dai moduli rubino non contiene un'implementazione.

Questa è la maggior parte di esso. Citiamo categorie tuttavia.

Una categoria è dichiarata non in parentesi angolari, ma tra parentesi. La differenza è che una categoria può essere definito per una classe esistente per espandere senza sottoclasse esso. Si può anche fare così per una classe di sistema. Come si può immaginare, è possibile utilizzare le categorie di implementare qualcosa di simile a mixin. E sono stati utilizzati in questo modo per un lungo periodo di solito come categoria a NSObject (la radice tipicadella gerarchia di ereditarietà), a tal punto che essi sono stati chiamati protocolli "informali".

E 'informale, perché 1- nessun tipo di controllo viene effettuato dal compilatore, e 2- attuazione dei metodi di protocollo è facoltativo.

Non è necessario oggi per usare categorie come i protocolli, soprattutto perché i protocolli formali possono ora dichiarano che alcuni dei loro metodi sono opzionali con la parola chiave @optional o richiesto (il default) con @required.

Le categorie sono ancora utili per aggiungere alcuni comportamenti specifici di dominio per una classe esistente. NSString è un obiettivo comune per questo.

E 'anche interessante notare che la maggior parte (se non tutti) degli impianti NSObject sono infatti dichiarati in un protocollo NSObject. Ciò significa che non è davvero convincente per utilizzare NSObject come superclasse comune per tutte le classi, anche se questo è ancora comunemente fatto per ragioni storiche, e ben ... perché non c'è nessun inconveniente per farlo. Ma alcune classi di sistema, come NSProxy, sono non NSObject.

Altri suggerimenti

spudorato: ObjectiveMixin

Si avvale della capacità di Objective-C di runtime di aggiungere metodi a una classe in fase di esecuzione (al contrario di categorie, che sono in fase di compilazione solo). Check it out, funziona abbastanza bene e in modo simile a mixins di Ruby.

Si può letteralmente mixin il codice utilizzando #include. Questo non è consigliabile ed è contro tutte le religioni in Objective-C, tuttavia funziona perfettamente.

Per favore, non farlo nel codice di produzione.

ad esempio nel file:

MixinModule.header (non deve essere compilato o copiati al target)

-(void)hello;

MixinModule.body (non deve essere compilato o copiati al target)

-(void)hello{
    NSLog(@"Hello");
}

nella classe intermedia:

@interface MixinTest : NSObject
#include "MixinModule.header"
@end

@implementation MixinTest
#include "MixinModule.body"
@end

caso utilizzo:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]){
    @autoreleasepool {
        [[[MixinTest new] autorelease] hello];
    }
    return 0;
}

Per favore, non farlo nel codice di produzione.

Questo è il mio introito su attuazione mixin in Objective-C, senza utilizzare direttamente il runtime Objective-C. Forse è utile a qualcuno: https://stackoverflow.com/a/19661059/171933

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top