Question

Dans Ruby, il y a des modules et vous pouvez étendre une classe en "mélangant" le module.

module MyModule
  def printone
    print "one" 
  end
end

class MyClass
  include MyModule
end

theOne = MyClass.new
theOne.printone 
>> one

En Objective-C, je trouve que j'ai un ensemble de méthodes communes dont je souhaite qu'un certain nombre de classes "héritent".De quelles autres manières puis-je y parvenir sans créer une classe commune et tout dériver de cette classe commune ?

Était-ce utile?

La solution

Modifier:changements ajoutés parce que certaines personnes pensent que je suis responsable des limitations d'Objective-C.

Réponse courte:tu ne peux pas.Objective-C n'a pas l'équivalent des mixins Ruby.

Réponse un peu moins courte:Objective-C a quelque chose avec sans doute la même saveur :protocoles.Les protocoles (interfaces dans certains autres langages) sont un moyen de définir un ensemble de méthodes qu'une classe qui adopte ces protocoles s'engage à mettre en œuvre.Cependant, un protocole ne fournit pas d'implémentation.Cette limitation empêche d'utiliser les protocoles comme équivalent exact aux mixins Ruby.

Réponse encore moins courte : Cependant, le runtime Objective-C dispose d'une API exposée qui vous permet de jouer avec les fonctionnalités dynamiques du langage.Ensuite, vous sortez du langage, mais vous pouvez avoir des protocoles avec des implémentations par défaut (également appelés protocoles concrets).La réponse de Vladimir montre une façon de procéder.À ce stade, il me semble que vous obtenez bien les mixins Ruby.

Cependant, je ne suis pas sûr de recommander cela.Dans la plupart des cas, d’autres modèles conviennent sans jouer avec le runtime.Par exemple, vous pouvez avoir un sous-objet qui implémente la méthode mixte (a un au lieu de est un).Jouer avec le runtime est acceptable, mais présente 2 inconvénients :

  • Vous rendez votre code moins lisible car il oblige les lecteurs à connaître bien plus que le langage.Bien sûr, vous pouvez (et devez) le commenter, mais rappelez-vous que tout commentaire nécessaire peut être considéré comme un défaut de mise en œuvre.

  • Vous dépendez de que mise en œuvre du langage.Bien sûr, les plateformes Apple sont de loin les plus courantes pour Objective-C mais n'oubliez pas Cocotron ou GnuStep (ou Etoilé) qui ont des runtimes différents, qui peuvent ou non être compatibles avec ceux d'Apple à cet égard.

En remarque, j'indique ci-dessous que les catégories ne peuvent pas ajouter d'état (variables d'instance) à une classe.En utilisant l'API d'exécution, vous pouvez également lever cette limitation.Cela dépasse cependant la portée de cette réponse.

Longue réponse:

Deux fonctionnalités Objective-C semblent possibles :catégories et protocoles.Les catégories ne sont pas vraiment le bon choix ici, si je comprends bien la question.La bonne fonctionnalité est un protocole.

Laissez-moi vous donner un exemple.Supposons que vous souhaitiez qu'un certain nombre de vos classes aient une capacité spécifique appelée « chanter ».Ensuite vous définissez un protocole :

@protocol Singer
    - (void) sing;
@end

Vous pouvez maintenant déclarer que n’importe laquelle de vos propres classes adopte le protocole de la manière suivante :

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

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

En déclarant qu'ils adoptent le protocole, ils s'engagent à mettre en œuvre les sing méthode.Par exemple:

@implementation Rectangle

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

@end

@implementation Car

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

@end

Ensuite, vous utilisez ces classes par exemple comme ceci :

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

Notez que les chanteurs du tableau n’ont pas besoin d’avoir une superclasse commune.Notez également qu'une classe ne peut avoir qu'une seule superclasse, mais plusieurs protocoles adoptés.Notez enfin que la vérification du type est effectuée par le compilateur.

En effet, le mécanisme du protocole est l'héritage multiple utilisé pour le modèle de mixage.Cet héritage multiple est sévèrement limité car un protocole ne peut pas ajouter de nouvelles variables d'instance à une classe.Un protocole décrit uniquement une interface publique que les adoptants doivent mettre en œuvre.Contrairement aux modules Ruby, il ne contient pas d'implémentation.

C'est le plus.Mentionnons cependant les catégories.

Une catégorie n’est pas déclarée entre crochets, mais entre parenthèses.La différence est qu'une catégorie peut être définie pour une classe existante afin de l'étendre sans la sous-classer.Vous pouvez même le faire pour une classe système.Comme vous pouvez l'imaginer, il est possible d'utiliser des catégories pour implémenter quelque chose de similaire au mixin.Et ils ont été utilisés de cette façon pendant longtemps, généralement comme catégorie pour NSObject (la racine typique de la hiérarchie successorale), à ​​tel point qu'on les qualifiait de protocoles « informels ».

C'est informel car 1- aucune vérification de type n'est effectuée par le compilateur, et 2- l'implémentation des méthodes de protocole est facultative.

Il n'est pas nécessaire aujourd'hui d'utiliser des catégories comme protocoles, d'autant plus que les protocoles formels peuvent désormais déclarer que certaines de leurs méthodes sont facultatives avec le mot-clé @optional ou obligatoire (valeur par défaut) avec @required.

Les catégories sont toujours utiles pour ajouter un comportement spécifique à un domaine à une classe existante. NSString est un objectif commun pour cela.

Il est également intéressant de souligner que la plupart (sinon la totalité) des NSObject les installations sont en effet déclarées dans un NSObject protocole.Cela signifie qu'il n'est pas vraiment obligatoire d'utiliser NSObject en tant que superclasse commune à toutes les classes, bien que cela soit encore couramment fait pour des raisons historiques, et bien...car il n’y a aucun inconvénient à le faire.Mais certaines classes système, comme NSProxy, sont pas NSObject.

Autres conseils

Shameless plug: ObjectiveMixin

Il profite de la capacité d'exécution Objective-C d'ajouter des méthodes à une classe d'exécution (par opposition aux catégories, qui sont à la compilation seulement). Check it out, cela fonctionne assez bien et de façon similaire aux mixins de Ruby.

Vous pouvez mixin littéralement le code à l'aide #include. Ce n'est pas souhaitable et est contre toutes les religions en Objective-C, fonctionne cependant parfaitement.

S'il vous plaît, ne le faites pas dans le code de production.

par exemple dans le fichier:

MixinModule.header (ne doit pas être compilé ou copié à la cible)

-(void)hello;

MixinModule.body (ne doit pas être compilé ou copié à la cible)

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

en classe mixin:

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

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

cas d'utilisation:

#import <Foundation/Foundation.h>

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

S'il vous plaît, ne le faites pas dans le code de production.

Ceci est mon avis sur la mise en œuvre Mixins en Objective-C, sans utiliser le moteur d'exécution Objective-C directement. Peut-être qu'il est utile à quelqu'un: https://stackoverflow.com/a/19661059/171933

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top