Types de données abstraits
Thèmes abordés
• Les problèmes du génie logiciel
Coûts de dé eloppement – Coûts de développement – Coûts des non-qualités
• Comment concevoir des bibliothèques efficaces
– Notion de type de données abstraits – Différents points de vue
• Concepteur
• Utilisateur
• Utilisateur – Un exemple concret – Analyse
Coûts du développement
• Un cas concret
Le cas A is E rope – Le cas Avis Europe
– Pourquoi des projets de développement logiciel échouent-ils ?
Analyse et programmation 2 - Les types de donnée abstraits 2
Les grands problèmes du génie logiciel
Coûts du développement
• Comment améliorer l’efficacité ?
18%
9%
15%
20% Activités
productives
Coûts des non-qualités
• Quelques conséquences des défauts logiciels
Analyse et programmation 2 - Les types de donnée abstraits 4
Les grands problèmes du génie logiciel
Introduction à la complexité logicielle
• Origines de la complexité
Comment développer mieux et moins cher
• Maîtriser la complexité
• Réutiliser du code existant
• Capitaliser les efforts
Analyse et programmation 2 - Les types de donnée abstraits 6
Les types de donnée abstraits
Maîtriser la complexité : diviser pour régner grâce à la modularité
• Découper un problème en modules.
A ssi indépendants q e possible – Aussi indépendants que possible.
– Faciles à comprendre.
– Testables.
• Quelles découpes en modules semblent judicieuses ?
Réduire les coûts de développement – la réutilisation de code
• Résoudre une fois pour toute une famille de problèmes
E emple : logiciel tilisant les nombres comple es – Exemple : logiciel utilisant les nombres complexes.
• Combien de fois seront programmés la somme, le produit de 2 nombres complexes ?
• Intérêt de créer des fonctions réutilisables pour ces opérations.
• Bibliothèques d’usage général
– Le calcul avec les nombres complexes est un problème général.
– Pas lié à une application particulière.
Analyse et programmation 2 - Les types de donnée abstraits 8
pp p
– Intérêt de créer une bibliothèque générale, réutilisable.
– Une telle bibliothèque existe-t-elle déjà ?
Les types de donnée abstraits
Capitaliser les efforts
• Abstraction
– Intérêt d’une fonction s’il faut la lire pour comprendre son effet?
– Intérêt d une fonction s il faut la lire pour comprendre son effet?
– Comment continuer à développer dans un projet de plusieurs millions de lignes de code s’il faut tout mémoriser ?
– Abstraction :
• Créer des fonctions offrant un service clair.
• Compréhensible et utilisable sans lire le code.
• Permet de traiter des problèmes de haut niveau, en s’affranchissant des problèmes de niveau inférieur déjà résolus.
• Isolation entre modules
– Si l’interface d’un module est juste, la correction ou la modification d’une fonction n’a pas d’influence sur le code utilisateur.
– Sécurisation des développements.
Capitaliser les efforts – abstraction et isolation Logiciel de
Quels modules sont réutilisables ?
Circuit électrique
Réponse
Liste de simulations simulation électrique
Modèle de
Analyse et programmation 2 - Les types de donnée abstraits 10
Nombres complexes Equations
différentielles Réponse
fréquentielle Réponse temporelle Modèle de
composant passif
Les types de donnée abstraits
Idée directrice
• Parallèle avec les types simples du langage C
Le t pe int : représente n entier – Le type int : représente un entier.
– Est fourni avec des opérations : + - / * %
– Il n’est pas nécessaire de connaître la représentation interne ou les algorithmes de ces opérations pour les utiliser.
• Faire de même pour des types plus complexes
– Créer un type, dont la représentation interne est cachée.
– Offrir les opérations de haut niveau nécessairesOffrir les opérations de haut niveau nécessaires.
Définition
• Terminologie
TDA : T pe de données abstrait – TDA : Type de données abstrait
– Dans la littérature anglaise : ADT (Abstract Data Type)
• Un TDA, c’est
– Un type de données.
– Doté d’un ensemble d’opérations.
– Dont les détails d’implémentation restent cachés (abstrait).
Analyse et programmation 2 - Les types de donnée abstraits 12
Les types de donnée abstraits
Exemple : Les nombres complexes
• Objectif
Conce oir ne bibliothèq e po r les opérations s r les nombres – Concevoir une bibliothèque pour les opérations sur les nombres
complexes
• Démarche
– Vision externe
• Quels sont les services attendus d’une telle bibliothèque ? – Vision interne
• Comment représenter un nombre complexe ?p p
• Quelle est la meilleure représentation ?
• Comment implanter les opérations ?
Exemple - Conception d’une interface abstraite – vue externe
typedef COMPLEXE...
void complexe initialiser(COMPLEXE* z);
void complexe_initialiser(COMPLEXE z);
void complexe_ecrire_cartesien(COMPLEXE* z, double re, double im);
void complexe_ecrire_polaire(COMPLEXE* z, double module, double argument);
double complexe_lire_reelle(COMPLEXE z);
double complexe_lire_imaginaire(COMPLEXE z);
double complexe_lire_module(COMPLEXE z);
double complexe_lire_argument(COMPLEXE z);
COMPLEXE complexe_oppose(COMPLEXE z);
COMPLEXE complexe conjugue(COMPLEXE z);
Analyse et programmation 2 - Les types de donnée abstraits 14
COMPLEXE complexe_conjugue(COMPLEXE z);
COMPLEXE complexe_somme(COMPLEXE z1, COMPLEXE z2);
COMPLEXE complexe_difference(COMPLEXE z1, COMPLEXE z2);
COMPLEXE complexe_produit(COMPLEXE z1, COMPLEXE z2);
COMPLEXE complexe_quotient(COMPLEXE z1, COMPLEXE z2);
Les types de donnée abstraits
Exemple - Conception de la structure de données – vue interne
• Déclaration du type – Implémentation cartésienne
typedef struct typedef struct {
double reel, imaginaire;
} COMPLEXE;
Exemple - Programmation des opérations – forme cartésienne
• Initialisation
void complexe_initialiser(COMPLEXE* z) {
complexe_ecrire_cartesien(z, 0.0, 0.0);
}
• Affectation
void complexe_ecrire_cartesien(COMPLEXE* z, double re, double im) {
z->reel = re;
z->imaginaire = im;
}
Analyse et programmation 2 - Les types de donnée abstraits 16
}
• Accès
double complexe_lire_reelle(COMPLEXE z) {
return z.reel;
}
Les types de donnée abstraits
Exemple - Programmation des opérations – forme cartésienne
• Somme
COMPLEXE complexe_somme(COMPLEXE z1, COMPLEXE z2) {
{
COMPLEXE resultat;
resultat.reel = z1.reel + z2.reel;
resultat.imaginaire = z1.imaginaire + z2.imaginaire;
return resultat;
• Produit}
COMPLEXE complexe_produit(COMPLEXE z1, COMPLEXE z2) {
COMPLEXE resultat;
COMPLEXE resultat;
resultat.reel = z1.reel * z2.reel - z1.imaginaire * z2.imaginaire;
resultat.imaginaire = z1.imaginaire * z2.reel + z1.reel * z2.imaginaire;
return resultat;
}
Attention. Mauvaise
Exemple d’utilisation
#include "complexes.h"
int main()
utilisation, car ne respecte pas l’abstraction du type.
{
COMPLEXE z1 = {3.0, 0.0}, z2, z3;
z2.reel = 0.0;
z2.imaginaire = 2.0;
z3 = complexe_somme(z2, z1);
printf("z3 = %lf + i . %lf\n", complexe_lire_reelle(z3), complexe_lire_imaginaire(z3));
t ("PAUSE")
Analyse et programmation 2 - Les types de donnée abstraits 18
system("PAUSE");
return 0;
}
Les types de donnée abstraits
Propagation des changements
• Ex : application d’environ 100’000 lignes de code
Utilisant intensi ement les nombres comple es – Utilisant intensivement les nombres complexes.
– Utilise la bibliothèque complexe cartésien.
– Accède directement aux champs : COMPLEXE z1 = {3.0, 0.0};
• Pour des raisons de performance, on doit changer de
bibliothèque et passer en représentation polaire.
Exemple d’utilisation correcte
#include "complexes.h"
int main() int main() {
COMPLEXE z1, z2, z3;
complexe_initialiser(&z1);
complexe_initialiser(&z2);
complexe_ecrire_cartesien(&z1, 3, 0);
complexe_ecrire_cartesien(&z2, 0, 2);
z3 = complexe_somme(z2, z1);
printf("z3 = %lf + i . %lf\n",
Analyse et programmation 2 - Les types de donnée abstraits 20
p t ( 3 % . % \ ,
complexe_lire_reelle(z3), complexe_lire_imaginaire(z3));
system("PAUSE");
return 0;
}
Les types de donnée abstraits
Exemple - Conception de la structure de données – vue interne
• Avec un TDA, le programme application devrait être indépendant de l’implémentation
indépendant de l implémentation.
• 2
èmeimplémentation possible du type complexe :
typedef struct {
double module, argument;
} COMPLEXE;
Exemple - Programmation des opérations – forme polaire
• Initialisation
void complexe_initialiser(COMPLEXE* z) {
complexe_ecrire_polaire(z, 0.0, 0.0);
}
• Affectation
void complexe_ecrire_cartesien(COMPLEXE* z, double re, double im)
{
z->module = sqrt(re * re + im * im);
z >argument = atan2(im / re);
Analyse et programmation 2 - Les types de donnée abstraits 22
z->argument = atan2(im / re);
}
• Accès
double complexe_lire_reelle(COMPLEXE z) {
return z.module * cos(z.argument);
}
Les types de donnée abstraits
Exemple - Programmation des opérations – forme polaire
• Somme
COMPLEXE complexe_somme(COMPLEXE z1, COMPLEXE z2) {
{
COMPLEXE resultat;
double reel, imaginaire;
reel = complexe_lire_reelle(z1) + complexe_lire_reelle(z2);
imaginaire = complexe_lire_imaginaire(z1) + complexe_lire_imaginaire(z2);
complexe_ecrire_cartesien(&resultat, reel, imaginaire);
return resultat;
}
• Produit
COMPLEXE complexe_produit(COMPLEXE z1, COMPLEXE z2)
Implémentation polaire – le programme application est inchangé !
#include "complexes.h"
int main() int main() {
COMPLEXE z1, z2, z3;
complexe_initialiser(&z1);
complexe_initialiser(&z2);
complexe_ecrire_cartesien(&z1, 3, 0);
complexe_ecrire_cartesien(&z2, 0, 2);
z3 = complexe_somme(z2, z1);
printf("z3 = %lf + i . %lf\n",
Analyse et programmation 2 - Les types de donnée abstraits 24
p t ( 3 % . % \ ,
complexe_lire_reelle(z3), complexe_lire_imaginaire(z3));
system("PAUSE");
return 0;
}
Les types de donnée abstraits
Comparaison des 2 implémentations
• Points communs
– L’interface est absolument identique – L interface est absolument identique.
– L’une ou l’autre forme est interchangeable
• Sans aucun changement dans l’application.
• Différences
– L’implémentation cartésienne est un peu plus simple en général.
– L’implémentation polaire est plus efficace pour les produits.
• Laquelle choisir ?
– Point de vue fonctionnel : elles sont identiques.
– Point de vue performance :
• Dépend des opérations effectuées le plus couramment dans l’application.
• Dans bien des cas, l’un ou l’autre conviendrait très bien.
Méthodes et données privées
• La structure de données d’un TDA est nécessairement privée (cachée)
privée (cachée)
• Certaines fonctions manipulant un TDA peuvent aussi être cachées.
– Fonctions utilisées pour réaliser certaines opérations.
– Ne devant surtout pas être employée directement par l’utilisateur du TDA.
• Exemple : fonction qui modifie l’état interne du TDA sans effectuer
Analyse et programmation 2 - Les types de donnée abstraits 26
Exemple : fonction qui modifie l état interne du TDA sans effectuer les contrôles de cohérence nécessaire.
Les types de donnée abstraits
Paradigme (modèle de programmation) TDA
• Abstraction de données
Identifier les caractéristiq es importantes par rapport a – Identifier les caractéristiques importantes par rapport aux
opérations
• Encapsulation
– Intégrer ces données dans une entité logicielle (structure) – Structure de données + opérations
• Modularité
Diviser un gros système en entités plus petites – Diviser un gros système en entités plus petites
Opérations courantes d’un TDA
• Initialiseurs ou constructeurs
Préparent o créent ne instance d TDA – Préparent ou créent une instance du TDA.
• Modificateurs
– Modifient les valeurs du TDA.
• Sélecteurs
– Interrogent et retournent des valeurs du TDA.
• Itérateurs
Analyse et programmation 2 - Les types de donnée abstraits 28
– Permettent le parcours du TDA.
Les types de donnée abstraits
Des points de vue différents
• Le point de vue externe de l’utilisateur du TDA
Q els sont les ser ices offerts par ce TDA ? – Quels sont les services offerts par ce TDA ? – Le TDA répond-il bien à mon besoin ? – Quelles sont les opérations disponibles ? – Le TDA est-il suffisamment performant ?
• Le point de vue interne du concepteur du TDA
– Comment représenter l’information du TDA ? Comment implanter efficacement les opérations ? – Comment implanter efficacement les opérations ? – Comment le TDA sera-t-il utilisé ?
– Quelles opérations doivent être optimisées ?
Des points de vue différents
Application
Spécification Application Utilisation du TDA
Programmeur d'application utilisateu
du TDA
frontière
Analyse et programmation 2 - Les types de donnée abstraits 30
Réalisation
Implémentation du TDA
Concepteur du TDA
Les types de donnée abstraits
Isolation entre couches – Programmation par contrat
Application Application
Spécification (interface du TDA)
( )
Isolation entre couches – Programmation par contrat
• Programmation par contrat
Chaq e fonction (opération d TDA) pe t commencer par des – Chaque fonction (opération du TDA) peut commencer par des
contrôles de cohérence
• Des paramètres reçus.
• De l’état interne du TDA.
– En cas d’incohérence (contrat non respecté):
• L’opération n’est pas effectuée.
• Permet de garantir le maintien de la cohérence interne du TDA.
Analyse et programmation 2 - Les types de donnée abstraits 32
• Exemple: TDA Liste de capacité limitée à 100 éléments.
– Si la liste est pleine, l’opération liste_ajouter renvoie une erreur plutôt que d’enregistrer anormalement un 101èmeélément.
Les types de donnée abstraits
Caractérisation complète de variables de TDA
COMPLEXE z1, z2, z3;
• Identité
– La variable elle-même (son adresse) : z1, z2, z3, …
• Etat
– Ses valeurs à un instant donné.
• Opérations p
– L’ensemble des fonctions qui s’y appliquent.
Critères de qualité d’un TDA
• Facile à comprendre et à utiliser.
Condition préalable indispensable à son tilisation – Condition préalable indispensable à son utilisation.
• Séparation claire de la spécification et de la réalisation.
– Garantir l’indépendance du code qui utilise le TDA par rapport à sa mise en œuvre.
• Abstraction des données, privé.
– Pour garantir la séparation spécification et réalisation.
Effi ité
Analyse et programmation 2 - Les types de donnée abstraits 34
• Efficacité
– Performance des algorithmes mis en œuvre.
• Stabilité de la spécification
– Pour éliminer les risques de propagation des changements dans le code qui utilise le TDA.
Les types de donnée abstraits
Avantages
• Briques de base pour une conception modulaire.
C t ti d TDA t d’ li ti l
• Construction de TDA et d’applications complexes
– par assemblage de TDA plus simples.
• Possibilité de tester et de valider par étape le logiciel.
• Approche de développement efficace validée.
Inconvénients
• Coût en performances.
L i t d té l ût
• Les services sont documentés, par leur coût.
• L’interface d’un TDA doit être stable, requiert un effort de conception.
Analyse et programmation 2 - Les types de donnée abstraits 36
Qu’avons-nous appris ?
• Problèmes liés au développement de logiciels complexes
• Solution : découpage d’une application en TDA
• Solution : découpage d une application en TDA
– Séparation des problèmes.
– Facilitation de la programmation et de la maintenance.
– Favorable au test.
• Démarche pour la conception d’un TDA
– Identifier un TDA.
– Identifier ses opérations.
– Implanter les opérations du TDA.
• Démarche pour l’utilisation d’un TDA
– Respecter l’abstraction en utilisant seulement ses opérations.
– Ne jamais accéder directement aux données internes.