Rappels

Accesseurs

On appelle Accesseurs les méthodes qui permettent de lire et d'assigner une propriété d'un objet, souvent directement lié à une variable d'instance. Exemple:

Object subclass: #Personne
  instanceVariableNames: 'nom prenom'
  classVariableNames: ''
  poolDictionaries: ''
  category: 'Sanbox'
Ici, nom et prenom sont deux variables d'instances. On ne peut pas accèder directement a une variable d'instance d'un objet (principe d'encapsulation). Un avantage en Smalltalk est de pouvoir garder le nom des variables d'instances en utilisant un message unaire pour les retourner:

nom
  ^ nom
et un message à mots-clé pour les assigner

nom: aString
  nom := aString
Notez bien qu'en objet un message est envoyé à un receveur. Si le receveur n'est pas spécifié, le système considère que c'est une variable.

luke := Personne new.
luke nom: 'Skywalker'.
luke prenom: 'Luke'.

Cascade

Si on ne précise pas de réponse dans une méthode c'est le receveur qui est renvoyé (soit ^ self implicite). L'accesseur nom: précédent équivaut à:

nom: aString
  nom := aString.
  ^ self.
On peut donc écrire en utilisant les cascades:

luke := Personne new
              nom: 'Skywalker';
              prenom: 'Luke'.

Tests

Les tests permettent de vérifier le bon comportement du code que nous écrivons. Par exemple, si on veut s'assurer qu'un objet Personne peut renvoyer ses initiales, nous pouvons écrire dans une classe:

TestCase subclass: #PersonneInitialsTest
  instanceVariableNames: ''
  classVariableNames: ''
  poolDictionaries: ''
  category: 'Sanbox'
les tests suivants:

testLukeSkywalkerInitialsShouldReturnLS
  |luke|
  luke := Personne new
    nom: 'Skywalker';
    prenom: 'Luke'.

  self assert: 'LS' equals: luke initials.


testHanSoloInitialsShouldReturnHS
  |han|
  han := Personne new
    nom: 'Han';
    prenom: 'Solo'.

  self assert: 'HS' equals: han initials.
Ce qui obligera à écrire dans la classe Personne:

initials
  ^ prenom first asString, nom first asString.

Héritage

Une classe peut hériter les propriétés d'une autre classe. On parle alors de sous-classe et de superclasse. C'est avec l'aggrégation un mécanisme de réutilisation, adapté lorsqu'un type est un sous-ensemble d'un autre. Par exemple, SmallInteger et LargeInteger sont des sous-classes d'Integer.

Object subclass: #Personne
  instanceVariableNames: 'nom prenom'
  classVariableNames: ''
  poolDictionaries: ''
  category: 'Sanbox'
On a donc Personne qui est une sous-classe d'Object. Comme Object définit la méthode #asString, on peut écrire:

luke := Personne new
              nom: 'Skywalker';
              prenom: 'Luke'.
luke asString.

Conditions

Voir les classes Boolean, True et False, protocole controlling. Exemples:

Transcript open.
x := 11.
x > 10 ifTrue: [Transcript show: 'ifTrue'; cr].	
x > 10 ifFalse: [Transcript show: 'ifFalse'; cr].
x > 10	
   ifTrue: [Transcript show: 'ifTrue'; cr]
   ifFalse: [Transcript show: 'ifFalse'; cr].
x > 10	
   ifFalse: [Transcript show: 'ifFalse'; cr]
   ifTrue: [Transcript show: 'ifTrue'; cr].

TP

Exercice 1

Créez la catégorie Exercices dans le browser. Toutes les classes développées par la suite devront se trouver dans cette catégorie. Implémentez la classe Operation qui doit fonctionner comme suit (évaluez ce code dans un Workspace):
  1. 
    a := Operation new.
    a result.
    
    Doit retourner 0 (qui est la valeur initiale de l'opération).
  2. 
    b := Operation new.
    b add: 2.
    b add: 3.
    b result.
    
    Doit retourner 5 (0 + 2 + 3).
  3. 
    Operation new
      add: 2;
      add: 4;
      divideBy: 2;
      result.
    
    Doit retourner 3.
Les messages: