Objets et classes
Objets - les composants de l’application Une application à l'exécution consiste en un ensemble d’objets Un objet fournit un service à d’autres objets Un objet comprend un ensemble de messages (interface) Une méthode sert chaque message Un état caché (composé de variables) qui persiste Etat caché m 1 interface m 2 m 3 Seules les méthodes m1,m2 et m3 peuvent manipuler les variables de l’état
Exemple : Prog.java main(){ /* procedure qui démarre l ’application */ Ecran monEcan Cercle cir1, cir2; Carre car1 / * Créer les nouveaux objets */ cir1= new Cercle(1,2,2,monEcran) cir2 = new Cercle(4,2,5,monEcran) car1 = new Carre(2,3, 2,5,monEcran); /* Afficher les formes */ cir1.dessiner(); cir2.dessiner(); car1.dessiner(); /* bouger cercle 1 avec les paramètres de cercle 2 */ cir1.bouger(cir2.xCoord(),cir2.yCoord()) } /* Les paramètres du messages doivent être connus avant l’envoie du message */
Objets 1 Création des formes car1 Écran cer1 main() 1 Création des formes Et le transfert d’une référence sur Écran cer2 2 Si un objet A possède une référence sur B, Alors A peut envoyer un message à B
result = obj.meth(arg1, arg2, arg3) Messages Un message, ou appel de méthode, est le moyen de communiquer entre objets Un message possède un format bien précis En Java, un argument (arg) et le résultat peuvent être Le nom d’un autre objet C-à-d : une référence sur un objet Ceci est le mécanisme de base pour la distribution d’informations dans un système à objets Ou une valeur simple (int, float, char, bool) result = obj.meth(arg1, arg2, arg3)
Classes Une classe décrit le comportement d’un objet : Les messages servis (l’interface) La méthode est exécutée pour chaque message Un constructeur est une méthode spéciale Elle est exécutée par tout objet lors de sa création Elle initialise les variables d’état Elle rend un nom unique pour l’objet au créateur C-à-d : une référence sur l’objet Créateur est soit le main() du programme, soit un autre objet Une classe est fournie par un programmeur
Exemple: classe Cercle class Cercle{ /* Données locales */ int radius, x, y; Ecran ec; /* Le constructeur */ public Cercle(int a, int b, int r, Ecran e) { radius = r; x=a; y=b; ec = e;} /* Les méthodes des messages */ public float surface() { return 3.14*radius * radius} public void bouger(int a,int b) { x = a; y = b;} public int xCoord() { return x;} public int yCoord() { return y;} public void dessiner() { ec.afficher(this) } }
Exemple: classe Carré class Carre{ int longeur, hauteur, x, y; Ecran ec; public Carre(int a, int b, int h, int l, Ecran e) { longeur=l; hauteur= h; x=a; y=b; ec = e;} public float surface() { return longeur*hauteur} /* Les méthodes restent les mêmes ! */ public void bouger(int a,int b) { x = a; y = b;} public int xCoord() { return x;} public int yCoord() { return y;} public void dessiner() { ec.afficher(this) }}
Classes Une classe est fournie par un programmeur Le code de la classe est recherché dans une librairie lors de la compilation, C’est également le cas pour les librairies comme stdio en Unix/C Sinon, la classe peut être recherchée pendant l'exécution Quand un objet crée lui-même un nouvel objet d’une classe C, le support d’exécution (le run-time) recherche la classe C dans le système de fichiers ou sur le réseau au moment de l’exécution que le premier objet invoque new C()
Prog.class à l’exécution main(){ Ecran monEcan - allouer une référence pour monEcran Cercle cir1, cir2; - allouer 2 références supplémentaires Carre car1 - allouer une référence pour un Carre cir1= new Cercle(1,2,2,monEcran) - demander à l’environnement de trouver la classe Cercle et de la charger en mémoire cir2 = new Cercle(4,2,5,monEcran) car1 = new Carre(2,3, 2,5,monEcran); A l’aide des classes, les objets sont créés cir1.dessiner(); car1.dessiner(); cir1.bouger(cir2.xCoord(),cir2.yCoord() - L’envoie des messages entre les objets} La liaison du code est faite tardivement On est donc sûr d’avoir la version la plus récente
La programmation par composants Classes et Objets La programmation par composants
Décomposition logique La programmation objet permet la décomposition d’un problème en sous-problèmes dont la solution peut être poursuivie indépendamment Par de programmeurs différents Façon d’aborder le problème de taille des applications de nos jours P.ex: la classe Carré et la classe Cercle ont été créées indépendamment mais sont utilisées ensemble dans la même application
Information Hiding La programmation objet rend plus facile l’intégration de composants Un composant a simplement besoin de connaître l’interface d’un autre composant pour l’utiliser On peut donc modifier l’implantation d’une classe sans toucher aux autres composants de l’application Notamment, le choix des variables dans une classe ainsi que les algorithmes choisis pour les méthodes Information hiding Si un programmeur n’a pas besoin de savoir alors il ne doit pas savoir
La protection Les erreurs dans un objet sont contenues Elles ne peuvent pas nuire aux variables dans d’autres objets P.ex: si dans l’objet cir1, l’exécution de la méthode surface provoque un débordement de valeur, cir2 et car1 ne sont pas touchés Cela n’est pas le cas avec C à cause des pointeurs ! Mais l’appelant de cir1.surface() est bloqué en attente d’une réponse Il faut un mécanisme supplémentaire : le traitement d’exceptions
Support langage Un langage de programmation est censé nous fournir un ensemble de mécanismes pour faciliter la construction d’applications P.ex: la procédure ou la fonction Décrit les tâches qui s'exécutent souvent dans un programme Et évite donc les répétitions de portions de code L’environnement d’exécution (le runtime) est sensé mettre ces mécanismes en œuvre
Support langage Les modules (les libraires) Un module comprend un ensemble de procédures P.ex: ceux importés par les programmes C Satisfait le besoin de réutiliser le code et la connaissance d’autres programmeurs Le code est intégré dans le programme lors de la compilation (généralement) Un module existe seulement pendant la compilation Si on modifie un module après, le programme ne s’aperçoit pas de ces changements !
Support langage Les pointeurs en C et les fichiers Satisfont le besoin de partager des données entre programmes et entre composants P.ex: pour échanger une structure Cercle en C/Unix Convertir le cercle en une chaîne d’octets (STREAM) et l’écrire dans un fichier pour un autre programme Ou bien, passer un pointeur pour la structure en argument à la fonction destinataire Mais manque de sémantique ! On envoie une chaîne d’octets et non un cercle !
Support langage : le modèle d’objets Tout objet qui possède une référence sur un objet O peut lui envoyer un message ! Un objet est une donnée partagée mais avec plus de sémantique Un pointeur sur une structure Cercle peut être utilisé pour lire et écrire les données dans la structure Mais une référence sur un objet Cercle peut être utilisée pour dessiner ou calculer la surface du Cercle Seule la classe de l’objet décide comment l’objet est modifié ou lu Une utilisation de la cercle qui est toujours correcte
La responsabilité L’interface sert comme un contrat entre un objet et ses clients En Java, on peut définir une interface public interface Forme{ public float surface(); public void bouger(int a, int b); public void dessiner(); public int xCoord(); pubic int yCoord();} Une interface en Java est comme une classe mais sans le code des méthodes
La responsabilité Une classe peut réaliser une interface La classe est censée fournir une méthode pour toutes celles de l’interface Les entêtes de Cercle et Carré peuvent être écrites ainsi : « class Cercle implements Forme » ou « class Carre implements Forme » Le client est alors assuré qu’un objet d’une classe qui réalise une interface comprend tous les messages de cette interface
Exemple: classe Carré class Carre implements Forme{ int longeur, hauteur, x, y; Ecran ec; public Carre(int a, int b, int h, int l, Ecran e) { longeur=l; hauteur= h; x=a; y=b; ec = e;} public float surface() { return longeur*hauteur} public void bouger(int a,int b) { x = a; y = b;} public int xCoord() { return x;} public int yCoord() { return y;} public void dessiner() { ec.afficher(this) }}
La responsabilité - interface Utile pour le code qui manipule des objets de divers sorts (p.ex: dans la classe Ecran) void afficher(Forme f) On peut facilement ajouter des nouvelles classes pendant la vie de l’application où chaque classe implements Forme main(){ Cercle c1 = new Cercle(2,3,4); Carre c2 = new Carre (3,6,7,4); Forme f; /* 2 affectations légales */ f = c1; f=c2; /* Exploitation de l’interface */ f.dessiner(); float f1 = f.surface()
La responsabilité La programmation objet se concentre sur les message et non sur les données P.ex: Comment faut-il représenter la date ? 17.3.1999 ou 3/17/1999 ou 99.3/17 ? Question très vexante !! Dans le modèle d’objets Date est une classe avec l’interface: jour(), mois(), année() Pour un objet d de la classe date, le mois est donné par d.mois() La représentation interne de la date n’est pas importante
La responsabilité La programmation nécessite une modélisation du système que l’on code Mais comment choisir les classes pour une application ? Expérience ! Souvent beaucoup des essais sont nécessaires Il faut préciser les entités du système et puis les messages que ces entités sont censées comprendre Parfois, on est restreint par les classes dont on dispose déjà dans nos librairies Et puisqu’il est souvent préférable de réutiliser une classe que d’en coder une nouvelle ….
Reutilisabilité Une classe peut être réutilisée dans une autre application Un but de la programmation objet ! Parfois la classe ne convient pas à 100% P.ex: pour représenter une cercle en couleur, il faut modifier Cercle pour représenter la couleur P.ex: la classe Cercle ressemble beaucoup à la classe Carré, mais on ne peut pas utiliser l’une pour l’autre
Reutilisabilité Le principe ouvert - fermé i) Une classe doit être fermée par rapport à d’autres classes Le principe de la modularité et Information hiding Accès simplement via l’interface ; l’état interne reste caché ii) Une classe doit être suffisamment ouverte afin de pouvoir l’étendre facilement P.ex: définir une classe Cercle à partir d’une classe Carré Le mécanisme d'héritage (le prochain cours de Ciarán)
Un Exemple : Linda sécurisé Vers la pratique
Linda : rappel Un espace avec 4 tuples 8 é 9 salut 7 2.7 8 ok a b c Un processus lit un tuple avec l’opération in() - manque de sécurité !! Processus
SecOS - Linda sécurisé SecOS (Secure Object Space) Conçu pour un environnement ouvert Les programmes ne se font pas confiance Des données échangées sur le réseau peuvent être attaquées La communication sûre Les entrées dans un tuple peuvent être « chiffrées » Avec le chiffrement symétrique L’intégrité des messages Les entrées peuvent être signées Le chiffrement asymétrique
SecOS Une entrée dans un tuple SecOS est un paire k:o Une clé symétrique ou asymétrique et un objet Pour un tuple <k1:o1, k2:o2, k3:o3> Où k1 est une clé symétrique <k1:o1, k2:o2, k3:o3>.select(k1) rend l’objet o1 Si k1 est asymétrique, et k1 est son paire <k1:o1, k2:o2, k3:o3>.select(k1) rend o1 Rappel : lorsqu’on chiffre avec une clé d’un paire On déchiffre avec l’autre clé
SecOS : Pourquoi le modèle objet ? Protection P.ex: une clé (de la classe Key) ne doit pas être fabriquée Un objet clé contient une valeur secrète ; la comparaison des clés est effectuée avec la méthode Compare(Key k) de Key Cette valeur fait partie de l’état caché de l’objet Donc la clé ne peut pas être fabriquée dans le modèle d’objets Extensibilité SecOS comprend 4 000 lignes de code (petit !!) On l’a facilement implanté dans le plate-forme HyperNews 50 000 (lignes de code) ; 2ième exemple donné ce semestre
SecOS - quelques classes AsymKey - une clé asymétrique Bottom - l’objet passe-partout. LockedField - une entrée k:o dans un tuple LockedObject - un tuple SecOS SharedKey - une clé symétrique Space - l’espace Key - représente une clé symétrique ou asymétrique
SecOS - quelques classes Class Space LockedObject in(LockedField[] fieldSet) Crée un tuple template à partir des champs k:o et cherche un tuple dans l’espace qui correspond à ce template LockedObject in(LockedObject template) Utilise un tuple existant pour la recherche void out(LockedField[] fieldSet) Crée un tuple SecOS à partir des champs k:o et le met dans l’espace void out(LockedObject tuple)