2.4 Ajout de méthodes aux sous-classes de la classe Animal

Jusqu’à maintenant, toutes nos méthodes se trouvent dans la classe Animal. Tous les animaux ont donc le même comportement. Si l’on demande à une instance de la classe Perroquet ou Baleine de parler, elles vont toutes uniformément répondre je ne sais pas parler. Ainsi l’activation de la transmission:

Perroquet new nom: ’Polly’; parle
résulte dans l’affichage, dans le Transcript, de
Perroquet Polly: je ne sais pas parler
et la transmission:
Baleine new nom: ’Moby’; parle
résulte dans l’affichage de
Baleine Moby: je ne sais pas parler
C’est plutôt ennuyeux comme comportement.

Commençons par rendre le comportement des Perroquets un peu plus spécifique, puisque, nous le savons tous, certains perroquets savent apprendre à parler. Pour cela, retournons à notre explorateur de classes, sélectionnons la classe Perroquet et commençons à créer les protocoles initialize et actions, de la même manière que nous l’avons faite pour la classe Animal (cf. page 75). Comme nous avons donné la variable d’instance vocabulaire à notre classe Perroquet, une variable qui devrait contenir à tout instant le vocabulaire de chacun de nos perroquets particuliers, nous avons donc besoin d’une méthode d’initialisation de cette variable. Appelons-la vocabulaire: et mettons la dans le protocole initialize. Nous avons également besoin d’une méthode pour dire aux perroquets comment parler. Cette deuxième méthode s’appelera tout naturellement parle et nous le mettrons dans le protocole actions de la classe Perroquet. Voici ces deux méthodes (n’oubliez pas de faire accepter, avec les touches «Alt+s», chacune d’elles):

vocabulaire: aString  
    "apprend au perroquet un nouveau vocabulaire"  
    vocabulaire := aString  
 
parle  
    "fait parler le perroquet avec son vocabulaire"  
    self answer: vocabulaire
Testons alors le comportement des perroquets. Pour cela, créons un perroquet, donnons lui un nom et un vocabulaire et demandons lui ensuite de nous dire quelque chose. Par exemple, si nous entrons dans le Workspace l’expression suivante:
Perroquet new nom: ’Polly’;  
              vocabulaire: ’Screatch@#!? Go away’;  
              parle
et nous faisons un doIt (touches «Alt+d») sur cette expression, nous verrons apparaître dans le Transcript la ligne:
Perroquet Polly: Screatch#!? Go away
Nous avons pu créer au moins un animal qui sait dire autre chose que “je ne sais pas parler!

Comment SMALLTALK a-t-il procédé? D’abord nous avons, avec l’expression Perroquet new, créé une instance de la classe Perroquet. À cette instance nous avons ensuite envoyé le message nom: avec comme argument la chaine ’Polly’, le nom de tout perroquet dans les pays anglophones. L’instance de la classe Perroquet que nous venions de créer a cherché dans sa classe une méthode correspondant au sélecteur nom:. N’en trouvant aucune de ce nom, elle a cherché dans sa sur-classe, Oiseau. Cette classe ne contenant aucune méthode de ce nom non plus - elle ne contient aucune méthode - notre instance a continué alors à chercher une telle méthode dans la sur-classe de sa sur-classe, donc dans la classe Animal. Enfin, là, elle a trouvé la méthode de ce nom (de ce sélecteur):

nom: aString  
  "change le nom de l’animal en aString"  
  nom := aString
disant d’affecter à sa variable d’instance une nouvelle valeur, la valeur de l’argument que la transmission reçue contenait, la chaîne de caractères ’Polly’. À partir de cet instant nous pouvons parler de cette instance particulière de la classe Perroquet comme du perroquet Polly. Nous dirons que les instances de la classe Perroquet héritent de la méthode nom: de la classe Animal.

Notons bien que pour trouver la méthode correspondante au sélecteur d’un message, l’instance commence à chercher ce sélecteur dans sa classe, et si elle ne le trouve pas, remonte dans la chaîne de ses sur-classes, jusqu’à ce qu’elle trouve une méthode correspondante. C’est cette méthode qui sera alors exécutée. Si elle ne trouve nulle part une telle méthode - la recherche serait alors remontée jusqu’à la classe Object - SMALLTALK enverrait alors le message doesNotUnderstand: à l’instance, avec comme argument le sélecteur dont on ne trouve nulle part une implémentation, ce qui, normalement, provoque une erreur. Notons aussi que l’occurrence d’un nom de variable d’instance dans une méthode désigne toujours la variable d’instance du receveur du message - indépendamment de la classe dans laquelle se trouve la méthode.

Continuons l’analyse de notre transmission

Perroquet new nom: ’Polly’;  
              vocabulaire: ’Screatch@#!? Go away’;  
              parle
Après la transmission Perroquet new nom: ’Polly’, elle continue, en cascade – indiqué par le caractère point-virgule – par envoyer à notre perroquet nommé Polly le message vocabulaire: avec la chaîne de caractères ’Screatch#!? Go away’. Polly trouvant alors cette méthode dans sa propre classe peut l’éxecuter immédiatement et donne donc une nouvelle valeur à sa variable d’instance vocabulaire. Maintenant Polly se distingue de toutes les autres instances de la classe Perroquet par son nom et par son vocabulaire - bref, comme nous l’avons dit dans l’introduction, par les valeurs de ses variables d’instance.

PIC PIC

FIG. 2.9: Un Transcript et un Workspace montrant une interaction avec un perroquet


La figure 2.9 page 101 montre un Workspace avec un exemple de trois transmissions successives à un perroquet nommé Polly et les résultats de ces transmissions dans le Transcript. Dans cet exemple nous avons gardé une nouvelle instance de la classe Perroquet dans la variable globale Polly, afin de pouvoir lui envoyer plusieurs messages, l’un à la suite de l’autre. Pour chacune des lignes du Workspace, nous avons lancé un doIt avec les touches «Alt+d».19 Comme on peut le voir dans le Transcript, notre perroquet manque un peu d’intelligence: chaque fois qu’il apprend un nouveau vocabulaire, il oublie ce qu’il savait dire avant cet apprentissage. Imaginons alors que les perroquets puissent acquérir un vocabulaire de plus d’une phrase, et qu’ils en répondent, quand on leur demande de parler, avec une phrase aléatoire de ce vocabulaire.