Programmation 2 : quatrième cours

Programmation 2 : quatrième cours

Arnaud Labourel

8 ou 10 octobre 2018

Composition et délégation

Interaction entre les classes/instances

Une méthode peut utiliser les propriétés et méthodes d’un autre instance/classe :

Composition

Afin d’implémenter ses services, une instance peut créer des instances et conserver leur références dans ses attributs.

Agrégation

Une instance peut simplement posséder des références vers des instances :

Agrégation et délégation

Délégation du calcul de la distance à l’instance center de la classe Point :

Agrégation récursive

Il est possible de créer des structures récursives (les attributs de la classe contiennent des références vers une instance de la classe).

Utilisation d’une structure récursive

Utilisation d’une structure récursive

image

Utilisation d’une structure récursive

Utilisation d’une structure récursive

image

Utilisation d’une structure récursive

Utilisation d’une structure récursive

image

Agrégation récursive et méthodes

Il est ensuite possible d’implémenter des méthodes de façon récursive :

Parcours d’une structure récursive

image

Tests et développement

Tests

 

Règle

Un code non testé n’a aucune valeur.

Corollaire

Tout code doit être testé

Différents type de tests

  • Test unitaires : Tester les différentes parties d’un programme indépendamment les unes des autres.
  • Test de non régression : Vérifier que le nouveau code ajouté ne corrompt pas les codes précédents : les tests précédemment réussis doivent encore l’être.

Tests unitaires

  • Tester une unité de code : classe, méthodes, …

  • Vérifier un comportement :
    • cas normaux
    • cas limites
    • cas anormaux

Tests unitaires en java : JUnit

  • Un framework de test unitaire pour Java
  • S’appuie sur des assertions

Assertions JUnit (1/2)

  • assertTrue(boolean condition) : vérifie que condition est vraie.
  • assertFalse(boolean condition) : vérifie que condition est faux.
  • assertEquals(expected, actual) : vérifie que expected est à actual

    égal : equals pour les objets et == pour les types primitifs.
  • assertEquals(double expected, double actual, double delta) : vérifie que |expected − actual| ≤ delta
  • assertNull(Object object) : vérifie que la référence est null
  • assertNotNull(Object object) : vérifie que la référence n’est pas null

Assertions JUnit (2/2)

  • assertSame(Object expected, Object actual) : vérifie que les deux objets sont les mêmes (même référence).
  • assertArrayEquals(Object[] expected, Object[] actual) : vérifie si les deux tableaux contiennent les même éléments dans le même ordre.

  • fail() : échoue toujours

Message

Pour toutes les méthodes assert, il est possible de mettre un message en premier paramètre qui permet d’identifier l’assertion.

Gestion de version

Principe

  • Le code d’un projet est stocké dans un serveur.
  • Les développeurs soumettent des modifications avec des commentaires à chaque fois.
  • Le serveur conserve l’historique des mises à jour

Pourquoi la gestion de version ?

  • Pour travailler de manière harmonieuse en équipe sans se marcher dessus
  • Pour revenir en arrière en cas de problèmes
  • Possibilité de faire valider le code (via des tests) par le serveur et de rendre le déploiement automatique

Git

  • Logiciel de gestion de version le plus populaire
  • Serveur gratuit : github
  • Version libre de logiciel serveur : gitlab
  • Gestion de version décentralisée : la gestion de version se fait aussi en local

Utilisation de git

  • Via l’IDE : VCS (Version Control Systems) dans le menu d’IntelliJ
  • En ligne de commande : commande git

Exemple de commandes git

git clone adresse_projet

Clone un projet en local depuis un serveur

git add nom_de_fichier

Ajoute un fichier à la prochaine mise à jour.

git commit -m"commentaire"

Fait une mise à jour en local

git push

Pousse les mises à jour locales sur le serveur

git pull

Récupère les mises à jour du serveur en local

Types paramétrés

Stack d’Object

Supposons que nous ayons la classe suivante :

Problème de Stack d’Object

Nous rencontrons le problème suivant :

Nous avons également le problème suivant :

La solution : types paramétrés

Par conséquent, on souhaiterait pouvoir préciser le type des éléments :

Java nous permet de définir une classe Stack qui prend en paramètre un type. Ce type paramétré va pouvoir être utilisé dans les signatures des méthodes et lors de la définition des champs de la classe.

Lors de la compilation, Java va utiliser le type paramétré pour effectuer :

  • des vérifications de type ;
  • des transtypages automatiques ;
  • des opérations d’emballage ou de déballage de valeurs.

Définition de classes paramétrées

La nouvelle version de la classe Stack :

Emballage et déballage

Les types primitifs ne sont pas des classes :

Dans le cas d’un int, on doit utiliser la classe d’emballage (wrapper class) Integer :

Interdit : Stack<int> stack = new Stack<int>();

Autorisé :

Types primitifs

type classe d’emballage taille valeurs possibles
byte Byte 8 bits -128 à 127
short Short 16 bits -32768 à 32767
int Integer 32 bits  − 231 à 231 − 1
long Long 64 bits  − 263 à 263 − 1
float Float 32 bits
double Double 64 bits
char Character 16 bits caractère unicode
boolean Boolean non définie false ou true

Classes d’emballage

La classe Number sert de base pour toutes les classes d’emballage.

Elle contient les méthodes suivantes :

  • public int intValue()
  • public long longValue()
  • public float floatValue()
  • public double doubleValue()
  • public byte byteValue()
  • public short shortValue()

Classes d’emballage

Les classes d’emballage étendent Number :

  • Bytepublic static Byte valueOf(byte b)
  • Shortpublic static Short valueOf(short s)
  • Integerpublic static Integer valueOf(int i)
  • Longpublic static Long valueOf(long l)
  • Bytepublic static Byte valueOf(byte b)

Ils existent des constructeurs mais ils sont dépréciés (et donc pas à utiliser).

La classe Character

Les classes d’emballage ne contiennent pas que des méthodes liées aux instances :

  • public static Byte valueOf(byte b)
  • public static char charValue()
  • public static boolean isLowerCase(char ch)
  • public static boolean isUpperCase(char ch)
  • public static boolean isDigit(char ch)
  • public static boolean isLetter(char ch)
  • public static boolean isLetterOrDigit(char ch)
  • public static char toLowerCase(char ch)
  • public static char toUpperCase(char ch)
  • public static char toTitleCase(char ch)

Emballage et déballage automatique

Depuis Java 5, il existe l’emballage et le déballage automatique :

Attention

Il est important de noter que des allocations sont effectuées lors des emballages sans que des new soient présents dans le code.

Exemple : liste chaînée générique

On considère une liste chaînée de String

Exemple : liste chaînée générique

Nous la transformons en classe paramétrée de la façon suivante :

Plusieurs paramètres de types

Utilisation d’une classe avec plusieurs paramètres de types