UML 4 - Approche et modélisation objet Objets et Classes Diagramme de structure Analyse organique Bertrand LIAUDET Le cours contient 2 parties : une partie théorique (l’approche objet) et une partie pratique (la modélisation objet). La partie pratique peut être abordée indépendamment de la partie théorique. SOMMAIRE L’APPROCHE OBJET 4 Les 5 paradigmes de programmation de Stroustrup (C++) : vers la P.O.O ! 4 1 : PROCEDURE : pdg. de base, celui de la programmation procédurale 2 : MODULE (Package) : pdg. de la programmation modulaire : masquer l’information CLASSE : pdg. de l’abstraction des données : définir des types 4 : HERITAGE : pdg. de la programmation objet, celui de l’héritage 5 : GENERICITE : pdg. de la prog. générique (type variable, pattern, framework) Programmation objet vs. programmation procédurale Principe de la distinction Avantages de l’approche objet L’Objet 4 4 4 5 5 6 6 6 8 Présentation Etat 8 Comportement Identité Syntaxe UML Encapsulation Persistance des objets Transmission des objets UML – Approche objet - introduction – page 1/51 - Bertrand LIAUDET 8 8 8 9 9 9 9 Scénario de communication Communication entre objets Collaboration et communication 3 catégories d’objet en fonction de leur mode communication Le Message 9 10 10 10 12 Principes Synchronisation des messages Message synchrone Message asynchrone Message dérobant Message minuté La Classe 12 12 12 14 14 14 16 Classe, objet, instance Les attributs d’une classe Les principales catégories de méthodes L’Héritage 16 16 16 18 Héritage et représentation ensembliste 18 Vocabulaire ensembliste 18 Abstrait / Concret – Abstraction - Abstraire 19 L’héritage en programmation objet 19 Principe de substitution 20 Attention à l’héritage des associations ! 20 L’abstraction dans la programmation objet : un nouveau paradigme de programmation 20 Le Polymorphisme Principes Remarques méthodologiques 21 21 21 MODELISATION OBJET PREMIERE APPROCHE 22 1. L’objet et sa classe 22 Exemple du téléviseur Idée de la programmation objet Petite méthode de conception objet 22 23 23 2. Définition d’une classe 24 Les attributs Les opérations Formalisme UML 24 24 25 4. La classe comme interface 2 types d’interface : proposée et utilisée Formalisme UML UML – Approche objet - introduction – page 2/51 - Bertrand LIAUDET 27 27 27 Conception par les interfaces 5. Composant logiciel Présentation Deux types de modularité Abstraction Encapsulation Exemple 6. L’objet 29 31 31 31 31 31 32 34 Définition Principes techniques Lieux de déclaration – construction des objets Provenance des objets d’une méthode Syntaxe UML 7. La communication entre les objets : envoi de message Principe général de l’envoi de message Envoi de message et héritage Syntaxe UML du diagramme de séquence 8. Exemple complet : la bibliothèque Cahier des charges Analyse des interfaces Analyse des écrans Analyse des scénarios Diagramme des classes 9. Diagramme de classes et base de données : les classes « métier ». Classes-métier et classes organiques Classes-métier et base de données Relations entre le modèle BD et le modèle objet 34 34 34 34 35 35 35 35 35 37 37 37 39 40 42 43 43 43 43 10. L’affichage et les écrans 46 11. La gestion des collections 47 12. Les 3 relations fondamentales entre les objets (et les classes) : composition, utilisation, héritage 49 La composition L’utilisation (ou dépenndance) L’héritage 49 49 50 Première édition : automne 2007. Deuxième édition : novembre 2008. Troisième édition : octobre 2009 (chapitre première approche) – Mise à jour octobre 2010 Edition juillet 2015 UML – Approche objet - introduction – page 3/51 - Bertrand LIAUDET L’APPROCHE OBJET Le cours contient 2 parties : une partie théorique (l’approche objet) et une partie pratique (la modélisation objet). La partie pratique peut être abordée indépendamment de la partie théorique. Les 5 paradigmes de programmation de Stroustrup (C++) : vers la P.O.O ! Pour le compilateur, la différence entre le C et le C++ se limite à quelques mots clés supplémentaires et quelques types de données supplémentaires. Pour le programmeur, le passage d’une approche procédurale (on dit aussi fonctionnelle) à une approche « objet », c’est une nouvelle façon de programmer, un nouveau paradigme. Stroustrup, créateur du C++, distingue 5 paradigmes de programmation : PROCEDURE MODULE CLASSE HERITAGE GENERICITE 1 : PROCEDURE : pdg. de base, celui de la programmation procédurale Choisissez les procédures. Utiliser les meilleurs algorithmes que vous pourrez trouver. Utilisation de fonctions : définissez les entrées et les sorties. 2 : MODULE (Package) : pdg. de la programmation modulaire : masquer l’information Choisissez vos modules (fichiers avec des fonctions). Découpez le programme de telle sorte que les données soient masquées par les modules Le paradigme de la programmation modulaire est en partie rendue obsolète par l’usage de la programmation objet. Utilisation de static, extern, espace des noms : outils.c, outils.h (interface), utilisation.c. CLASSE : pdg. de l’abstraction des données : définir des types UML – Approche objet - introduction – page 4/51 - Bertrand LIAUDET Choisissez les types dont vous avez besoin. Fournissez un ensemble complet d’opérations pour chaque type. Il y a 3 sortes de types : • Les types définis par module (utilisation de référence, autre nom pour un objet) • Les types concrets définis par l’utilisateur : les classes (niveau interne, « organique ») « ces types ne sont pas « abstraits » : ils sont aussi réels que int et float. • Les types abstraits définis par l’utilisateur : les interfaces (niveau externe, « fonctionnel ») Fabriquer un type structuré consiste à regrouper des types (simples ou déjà structurés) dans un même type structuré : c’est déjà un mécanisme d’abstraction. La définition des types structurés et des opérations qui leurs sont associées correspond à la notion de TAD (type abstrait de donnée) et conduit directement à la notion de classe (rappelons qu’une classe c’est un type, en général structuré, auquel on ajoute des procédures). 4 : HERITAGE : pdg. de la programmation objet, celui de l’héritage Choisissez vos classes. Fournissez un ensemble complet d’opérations pour chaque classe. Rendez toute similitude explicite à l’aide de l’héritage. 5 : GENERICITE : pdg. de la prog. générique (type variable, pattern, framework) Choisissez vos algorithmes. Paramétrez-les de façon qu’ils soient en mesure de fonctionner avec une variétés de types et de structures de données appropriées. UML – Approche objet - introduction – page 5/51 - Bertrand LIAUDET Programmation objet vs. programmation procédurale Principe de la distinction Approche procédurale ou fonctionnelle : ce que le système fait • L’approche procédurale propose une méthode de décomposition basée uniquement sur ce que le système fait, c’est-à-dire aux fonctions du système On s’intéresse d’abord aux fonctions puis aux données manipulées par les fonctions. Les fonctions sont identifiées puis décomposées en sous-fonctions, et ainsi de suite jusqu’à l’obtention d’éléments simples programmables. • C’est la méthode cartésienne ou analytique. • L’architecture du système montre finalement un système unique avec une architecture hiérarchique des fonctions. Approche objet : démarche systémique : ce que le système est et fait • L’approche objet propose une méthode de décomposition non pas basée uniquement sur ce que le système fait, mais sur ce que le système est et fait. Autrement dit, on s’intéresse à des ensembles de fonctions associées chacun à un ensemble de données, le tout formant un objet. L’objet est une unité de services rendus (ses fonctions). Les fonctions et sont identifiées par objet et pour un objet et non plus à partir de l’ensemble du système. Les données sont identifiées par objet et pour un objet et non plus à partir des fonctions ou de l’ensemble du système. • C’est la méthode systémique : les objets collaborent entre eux pour constituer le système. On peut en rajouter ou en supprimer sans perturber les collaborations entre les objets non concernés. • L’architecture du système montre finalement un ensemble de sous-systèmes considérés comme des objets. C’est la description de ce que le système est. Chaque sous-système ou objet intègre sont jeu de fonctions. C’est la description de ce que le système fait à travers ce que font chacun des sous-systèmes ou objets. Avantages de l’approche objet • Stabilité de la modélisation par rapport aux entités du monde réel. • Construction itérative facilitée par le couplage faible entre les composants (les soussystèmes ou objets). • Possibilité d’une réutilisation les composants d’un développement à un autre. • Simplicité du modèle. La programmation objet est basée sur 5 concepts fondateurs : 1. Objet UML – Approche objet - introduction – page 6/51 - Bertrand LIAUDET 2. Message (l’échange entre deux objets) 3. Classe (la généralisation de l’objet) 4. Héritage (la factorisation de propriétés et de fonctions entre 2 classes) 5. Polymorphisme UML – Approche objet - introduction – page 7/51 - Bertrand LIAUDET L’Objet Présentation Objet = une identité + un état + un comportement On dit aussi : Objet = données (état) + méthodes (comportement, rôles, responsabilités) D’un point de vue abstrait, un objet informatique est une représentation d’un objet (une réalité) du monde extérieur. Cette représentation est caractérisée par des valeurs et des rôles à jouer. D’un point de vue informatique, un objet informatique est une variable avec un ou plusieurs champs qui seront manipulés (en lecture ou en écriture) par les fonctions associées à l’objet (les méthodes). Cette variable est aussi associée à des fonctions de plus haut niveau : les responsabilités ou rôles. Etat Valeurs instantanées des attributs (des données) d’un objet. Certaines parties de l’état peuvent évoluer au cours du temps. D’autres parties de l’état peuvent être constantes. Comportement Le comportement regroupe les méthodes (ou compétences ou responsabilités ou rôles) d’un objet. Les méthodes sont des fonctions qui permettent d’accéder aux valeurs des attributs d’un objet mais aussi des fonctions de plus haut niveau (responsabilités et rôles). Ces méthodes sont déclenchées par des stimulations externes : des messages envoyés par d’autres objets (c’est-à-dire des appels de méthodes). Identité Chaque objet possède une identité attribuée de manière implicite à la création de l’objet et jamais modifiée (c’est son adresse en mémoire). On peut donner un attribut clé à l’objet, qu’on appelle « clé naturelle » (par exemple, un numéro de sécurité sociale). Il s’agit toutefois d’un artifice de réalisation. Cette clé appartient à l’état de l’objet. Le concept d’identité est indépendant du concept d’état. Les objets sont différenciés par leurs noms (comme un nom de variable). UML – Approche objet - introduction – page 8/51 - Bertrand LIAUDET Toutefois, il est parfois difficile de nommer tous les objets : on peut donc les nommer du nom de leur classe, avec « : » devant. Syntaxe UML Les objets sont soulignés et placés dans un rectangle. Le nom de l’objet commence par une minuscule. Le nom de la classe commence par un majuscule. Objets nommés : olivier bertrand Objets sans noms : : Eleve : Professeur Encapsulation Pour accéder, en consultation ou en modification, à l’état d’un objet (à ses données), il faut passer par ses fonctions (ses méthodes). Il faut que ces fonctions soient appelées par d’autres fonctions qui peuvent être des méthodes du même objet ou d’un autre. Quand une méthode d’un objet 2 est appelée par une méthode d’un objet 1, on dit que l’objet 1 a envoyé un message à l’objet 2. Le message, c’est la méthode de l’objet 2. Donc, de façon générale, pour accéder à l’état d’un objet, il faut lui envoyer un message. Les méthodes sont l’interface obligatoire d’accès aux données d’un objet. Persistance des objets Un objet persistant sauvegarde son état dans un système de stockage permanent, de sorte qu’il est possible d’arrêter le processus qui l’a créé sans perdre l’information représentée par l’objet. C’est la passivation de l’objet. L’activation de l’objet consiste à reconstruire l’objet dans l’état dans lequel on l’avait sauvegarder. Par défaut, les objets ne sont pas persistants. Transmission des objets La transmission des objets consiste à faire passer un objet, par un moyen de communication quelconque, d’un système à un autre. Scénario de communication L’objet révèle son vrai rôle et sa vraie responsabilité lorsque, par l’intermédiaire de l’envoi de messages, il s’insère dans un scénario de communication (c’est-à-dire un cas d’utilisation concret du système). UML – Approche objet - introduction – page 9/51 - Bertrand LIAUDET Atterir : Tour de contrôle : Avion [en vol] L’objet « Avion » a dans ses méthodes la fonction « Atterrir ». L’objet « Tour de contrôle » a dans ses données un objet avion ou un pointeur sur un objet avion. Une méthode de l’objet « Tour de contrôle » peut donc envoyer un message à l’objet « Avion », c’est-à-dire faire appel à la fonction « Atterrir ». Autrement dit, envoyer un message, c’est appeler une fonction : un message, c’est un ordre impératif ! Communication entre objets Un système informatique peut être vu comme une société d’objets qui communiquent entre eux pour réaliser les fonctionnalités de l’application. Le comportement global d’une application repose sur la communication entre les objets qui la composent. De ce fait, l’étude des relations entre les objets du domaine est de première importance dans la modélisation objet. De plus, la première communication étant la communication entre les utilisateurs (acteurs externes) et le système, on peut aussi partir de l’analyse fonctionnelle pour trouver les classes. Collaboration et communication On peut parler indifféremment de communication ou de collaboration entre objet. Cependant, on parle plutôt de collaboration quand on décrit les communications nécessaires pour réaliser une fonctionnalité. La collaboration est plutôt finalisée. On parle par contre indifféremment de communication pour une communication atomique ou une collaboration. 3 catégories d’objet en fonction de leur mode de communication Un objet peut être : - émetteur de message sans jamais en recevoir, - destinataire de message sans jamais en émettre, - émetteur et destinataire de message. Les acteurs : client, thread UML – Approche objet - introduction – page 10/51 - Bertrand LIAUDET Ce sont des objets à l’origine d’une interaction. Ce sont des objets actifs. Il possède un « fil d’exécution » : un thread. Ils passent la main aux autres objets. On peut les appeler « client ». Les serveurs Ce sont des objets qui ne sont jamais à l’origine d’une interaction. Ils sont toujours destinataire des messages et ensuite ils répondent. Ce sont des objets passifs. Les agents Ce sont des objets qui cumulent les caractéristiques des acteurs et des serveurs. Ils peuvent interagir avec les autres objets à tout moment, de leur propre initiative ou suite à une sollicitation externe. Les agents permettent le mécanisme de délégation. Un client peut communiquer avec un serveur qu’il ne connaît pas via un agent. Les agents découplent les acteurs des serveurs en introduisant une indirection dans le mécanisme de propagation des messages. UML – Approche objet - introduction – page 11/51 - Bertrand LIAUDET Le Message Principes • L’unité de communication entre les objets est le message. • L’envoi de message s’apparente à un appel de fonction. • Cependant, il n’y a pas de correspondance statique prédéfinie entre le nom de l’appel et le code effectivement exécuté. En effet, l’appel de fonction de la programmation procédurale correspond à un branchement sur la fonction à partir d’une table d’adresses. Le mécanisme d’envoi de message consiste à remonter à la classe pour trouver la fonction et à remonter la hiérarchie des classes jusqu’à trouver la fonction correspondante tant au niveau du nom qu’au niveau des paramètres (polymorphisme). Si aucune fonction n’est trouvée, alors il y aura un message d’erreur. • Le message acquiert toute sa force d’intégration lorsqu’il est associé au polymorphisme et à la liaison dynamique. Synchronisation des messages La synchronisation précise la nature de la communication et les règles qui régissent le passage des messages. Message synchrone Une fois le message envoyé, l’expéditeur est bloqué jusqu’à ce que le destinataire accepte le message. Un appel de procédure est un message synchrone. Diagramme de collaboration correspondant : Envoi simple Un expéditeur Un destinataire Diagramme de séquence correspondant : Un expéditeur Un destinataire Envoi simple retour implicite UML – Approche objet - introduction – page 12/51 - Bertrand LIAUDET UML – Approche objet - introduction – page 13/51 - Bertrand LIAUDET Message asynchrone Il n’interrompt pas l’exécution de l’expéditeur. L’expéditeur envoie le message sans savoir quand ni même si le message sera traité par le destinataire. Diagramme de collaboration correspondant : Envoi simple Un expéditeur Un destinataire Diagramme de séquence correspondant : Un expéditeur Un destinataire Envoi simple retour implicite Ø Demi flèche ou flèche simple peuvent représenter les envois asynchrones. Message dérobant Un message dérobant déclenche une opération seulement si le destinataire s’est préalablement mis en attente du message. Dans le cas d’un message synchrone, l’expéditeur accepte d’attendre ; dans le cas d’un message dérobant, le destinataire accepte d’attendre. Envoi dérobant Message minuté Un message minuté bloque l’expéditeur pendant un temps donné, en attendant la prise en compte de l’envoi par le destinataire, ou la durée spécifiée dans le message. UML – Approche objet - introduction – page 14/51 - Bertrand LIAUDET Envoi minuté UML – Approche objet - introduction – page 15/51 - Bertrand LIAUDET La Classe Classe, objet, instance Une classe est la description d’un ensemble d’objets ayant les mêmes méthodes et les mêmes types de données. La classe peut être vue comme une extension de la notion de type. L’objet est la réalisation concrète de la classe : un objet est une instance d’une classe. Les objets apparaissent alors comme des variables de type classe. Les attributs d’une classe Ils sont définis par un nom, un type et éventuellement une valeur initiale. En général leur valeur est variable pour chaque instance de la classe (chaque objet). Toutefois, il existe des attributs constants au niveau de la classe : leur valeur sera la même pour chaque instance de la classe. Chat Nom :string Age : int Classe Chat : Chat Nom= ”Minou” Age= 1 Un objet Chat Les principales catégories de méthodes • Les constructeurs : pour créer les objets (création). • Les destructeurs : pour détruire les objets (destruction). • Les sélecteurs : pour renvoyer tout ou partie de l’état d’un objet (consultation). • Les modificateurs : pour modifier tout ou partie de l’état d’un objet (modification). • Les itérateurs : pour consulter le contenu d’une structure de données qui contient plusieurs objets. UML – Approche objet - introduction – page 16/51 - Bertrand LIAUDET • Les responsabilités ou rôles : ces méthodes correspondent aux fonction de haut niveau permettant la réalisation des fonctionnalités du système. En phase de conception, on s’intéresse surtout à ces méthodes. UML – Approche objet - introduction – page 17/51 - Bertrand LIAUDET L’Héritage Héritage et représentation ensembliste La représentation ensembliste permet de concevoir aisément la notion héritage : il suffit de concevoir l’inclusion d’un ensemble dans un autre. L’ensemble inférieur hérite des propriétés et des associations de l’ensemble supérieur : l’espèce hérite des attributs du genre. Un ensemble fait hériter ses attributs à tous les ensembles de niveaux inférieurs qu’il contient. Le genre fait hériter à toutes ses espèces. Cette organisation forme une hiérarchie, c’est la hiérarchie de spécialisation/généralisation, encore appelée hiérarchie « is-a », « est-un ». Formalisme ensembliste Chats Siamois Minou Minette Chaque élément d’un ensemble est aussi élément des ensembles qui le contiennent : « Minou », c’est mon chat siamois : il appartient à l’ensemble des Siamois, mais aussi à l’ensemble des Chats. Minette c’est le chat siamois de la voisine. Vocabulaire ensembliste Classe : ensemble, entité, table On peut considérer les classes comme des ensembles. Les attributs de la classe sont les attributs de l’ensemble. Chaque objet est un élément de l’ensemble. La notion rejoint celle d’entité et de table. Objet : élément, tuple L’objet correspond à un élément d’un ensemble. La notion rejoint celle de tuple (ligne de la table). UML – Approche objet - introduction – page 18/51 - Bertrand LIAUDET Sous-ensemble : espèce, classe-enfant, classe-mère L’espèce est un sous-ensemble de l’ensemble dont on parle : le siamois est une espèce de chat. Quand on parle d’un sous-ensemble, on dit aussi : « classe-enfant ». Quand on parle de l’ensemble incluant, on dit aussi : « classe-mère ». Sur-ensemble : genre, classe-mère Le genre est un « sur-ensemble » de l’ensemble dont on parle : le chat est le genre du siamois. Quand on parle d’un « sur-ensemble », on dit aussi : « classe-parent » ou « classe-mère ». Abstrait / Concret – Abstraction - Abstraire L’abstraction, c’est la classe ! Tous les noms d’ensemble sont abstraits : ce sont des abstractions. Une classe est donc toujours abstraite d’un certain point de vue : ce qui est concret, c’est l’objet instance de la classe. Les seules choses concrètes, ce sont les éléments de l’ensemble, c’est-à-dire les objets (Minou, mon chat siamois). Toutefois, UML définit particulièrement la classe abstraite, par opposition aux autres : une classe abstraite est une classe pour laquelle il n’y a pas d’instanciations d’objet. Elle sert uniquement à porter des spécifications en tant que classe-mère pour une classe « concrète ». Abstraire Abstraire, c’est remonter du concret à l’abstrait, donc des objets à la classe qui les englobe. Par exemple de Minou et Minette au Siamois, ou de Minou et Minette au Chat. Abstraire, c’est aussi remonter de l'espèce au genre, c’est-à-dire d’une classe-enfant à une classe-parent. Par exemple du Siamois et de l’Angora au Chat. Abstraire consiste à trouver des attributs communs à plusieurs ensembles ou à plusieurs choses concrètes pour définir un ensemble qui portera ces attributs et qui inclura les ensembles ou les choses concrètes en question. L’héritage en programmation objet L’héritage est une technique qui permet de construire une classe (espèce) en lui faisant hériter des attributs et des méthodes d’autres classes (genre, classe-parent, classe-mère, super-classe). L’héritage est utilisé pour : • construire de nouvelles classes qui héritent de caractéristiques existants déjà (héritage d’une classe fenêtre) • classer les objets (taxonomie) • le polymorphisme (possibilité qu’une même méthode se réalise différemment) • la conception abstraite (conception de « haut niveau », éloignée du codage concrêt). UML – Approche objet - introduction – page 19/51 - Bertrand LIAUDET Animal + crier () + manger () Chat Chien + crier () + crier () héritage avec polymorphisme Principe de substitution On peut substituer n’importe quel objet d’une super-classe par n’importe quel objet d’une sous-classe. La spécialisation ajoute des attributs et des opérations mais ni n’en détruit, ni n’en modifie. Attention à l’héritage des associations ! Les associations sont héritées mais pas complètement ! ! ! Le plus souvent, les contraintes des associations ne sont pas transmises automatiquement de la super-classe vers la sous-classe. Les contraintes sont le plus souvent traduites par un bout de code implanté dans la réalisation d’une opération. Comme les langages permettent la redéfinition des opérations dans les sous-classes, les programmeurs peuvent involontairement introduire des incohérences entre la spécification d’une super-classe et sa réalisation dans une des sous-classes. L’abstraction dans la programmation objet : un nouveau paradigme de programmation L’abstraction consiste à regrouper les éléments qui se ressemblent et à distinguer des structures de plus haut niveau d’abstraction, débarrassées de détails inutiles. La classe décrit le domaine de définition d’un ensemble d’objets. Les généralités sont contenues dans la classe. Les particularités sont contenues dans les objets. Avec les langages-objet, le programmeur peut construire une représentation informatique des abstractions de haut niveau correspondant aux usages mêmes de l’application, sans traduction vers des concepts de plus bas niveau, comme les variables, les types abstraits de données et les fonctions des langages non objet. UML – Approche objet - introduction – page 20/51 - Bertrand LIAUDET Le Polymorphisme Principes • Le polymorphisme décrit la caractéristique d’un élément qui peut prendre plusieurs formes (l’eau peut être à l’état solide, liquide ou gazeux). • Le polymorphisme désigne le principe qui fait qu’un nom d’objet peut désigner des objets de différentes classes issus d’une même arborescence. • Le polymorphisme désigne surtout le polymorphisme d’opération : la possibilité de déclencher des opérations différentes en réponse à un même message. • Le polymorphisme est lié à la notion d’héritage. On peut manipuler des objets dont le type est abstrait au niveau de la classe générale (abstraite). Le type deviendra concret quand l’objet deviendra concret et portera le type de sa classe spécialisée. • Le polymorphisme permet de manipuler des objets sans en connaître précisément le type : c’est un cas de généricité. Remarques méthodologiques • Le polymorphisme concerne le codage du corps des différentes méthodes. Par rapport à la conception, c’est une notion qui intervient à bas niveau. • Il ne faut pas penser l’analyse en terme de polymorphisme, mais en terme d’abstraction (et donc d’héritage). L’analyse en terme d’abstraction rend possible le polymorphisme au niveau concrêt. • Les bénéfices du polymorphisme sont un plus grand découplage entre les objets : ils sont avant tout récoltés durant la maintenance. UML – Approche objet - introduction – page 21/51 - Bertrand LIAUDET MODELISATION OBJET PREMIERE APPROCHE 1. L’objet et sa classe Dans le monde réel, on trouve des objets statiques (une table, une statue, etc.) et des objets coopératifs (une téléviseur, un robot-mixeur, etc.). Exemple du téléviseur Caractéristiques communes : le téléviseur abstrait Tous les téléviseurs n’ont pas les mêmes caractéristiques, mais tous les téléviseurs ont des caractéristiques communes. Ces caractéristiques sont de trois sortes : • les caractéristiques de ce qu’il est • les caractéristiques de ce qu’il fait (= de ce qu’il sait faire, =de ce qu’on peut en faire, =des services qu’il peut rendre, =des services qu’on peut lui demander) • les caractéristiques de ses relations avec le monde extérieur Caractéristiques de ce qu’il est Tous les téléviseurs ont une marque, un écran, des haut-parleurs, des circuits pour capter et transmettre l’image et le son, etc. Caractéristiques de ce qu’il fait (les services qu’il rend) Tous les téléviseurs ont un mécanisme de mise sous tension et d’arrêt, de changement de chaînes, de réglage des images et du son, etc. Caractéristiques de ses relations (interfaces) avec le monde extérieur Le téléviseur fonctionne si la prise de courant est branchée et si l’antenne ou le câble sont connectées. La télécommande permet d’adresser des signaux de changement d’état à la télévision pour utiliser ses services : allumer, éteindre, monter le son, baisser le son, choisir une chaîne, etc. Remarques : • Un téléviseur peut être déplacé d’une pièce à l’autre et continuer à fonctionner tant que ses relations avec le monde extérieurs sont maintenues. UML – Approche objet - introduction – page 22/51 - Bertrand LIAUDET • L’utilisateur d’un téléviseur doit uniquement savoir brancher la prise de courant, brancher l’antenne ou le câble, utiliser la télécommande. Il ne sait pas comment fonctionne un téléviseur. Abstrait et concret : classe et objet Cette description présente le concept de téléviseur. C’est une présentation abstraite (générale, théorique) : il n’est pas question d’un téléviseur réel, concret. Cette description correspond à la notion de classe (analogue à la notion de type en programmation procédurale). Tous les téléviseurs concrets sont construit à partir du même plan de base. Ce sont les objets (analogue à la notion de variable en programmation procédurale). Gestion des pannes En cas de panne du téléviseur, on cherche le problème soit au niveau de ses dépendances avec le monde extérieur, soit au niveau des services rendus par le téléviseur. Idée de la programmation objet L’idée de la programmation objet est de mimer ou simuler les objets du monde réel, que ce soit des objets statiques ou des objets coopératifs. Les objets statiques sont des objets qui seront utilisés par d’autres objets. Déterminer quels sont les objets du monde réel à considérer constitue la base de la démarche objet. C’est une démarche radicalement différente de la démarche procédurale qui consiste à séparer les données passives et les instructions de calcul sur ces données. Le paradigme objet unifie les données et les opérations dans un même module : l’objet. La compréhension d’un objet est obtenue à travers les informations qui le caractérise, mais aussi à travers les opérations ou les services qu’on peut lui demander, qu’on appelle encore ses responsabilités. Un objet est défini par un mode d’emploi, c’est-à-dire la liste des opérations qu’on peut appliquer à tous les objets de même nature. Cette compréhension est formalisée dans un modèle qui est la classe de l’objet. Petite méthode de conception objet A partir d’un cahier des charges : • Dans un premier temps on recense les noms communs et les verbes qu’on juge important. • Dans un second temps, on regroupe les opérations correspondant à des verbes avec les objets désignés par un nom commun. C’est la que se trouve la principale difficulté. La relation entre l’opération et l’objet doit valoir pour tous les objets de même nature (mettreSousTension () vaut pour tous les téléviseurs). En général, d’un point de vue grammatical, l’objet est complément d’objet (direct ou indirect) de l’opération (mettre sous tension quoi : le téléviseur, changer la chaîne de quoi : du téléviseur, etc.). UML – Approche objet - introduction – page 23/51 - Bertrand LIAUDET 2. Définition d’une classe Une classe est un modèle à partir duquel on pourra construire les objets. C’est un analogue de la notion de type. Les attributs Les attributs d’une classe peuvent être vus comme les champs d’un type structuré. Dans la classe, on peut donner des valeurs par défaut aux attributs. Une valeur par défaut peut être non modifiable : ces des constantes. Quand on crée un objet, les valeurs par défaut sont automatiquement affectées aux champs concernés. De plus, la visibilité et l’accès aux champs peuvent être réglementée. En général, les attributs sont privés : ils ne seront visibles que par les opérations de la classe. La classe comme type abstrait Le téléviseur a une alimentation, un ampli audio, un tube vidéo, etc. Ces caractéristiques sont des attributs du téléviseur. Le type de ces attributs est la classe correspondant à un objet alimentation, un objet ampli audio, etc. Cette approche permet de concevoir de façon à la fois abstraite et concrète : l’abstraction de la classe Alimentation sera finalement réalisée. Les opérations Une classe contient des opérations. Les opérations sont des procédures et des fonctions. Distinction entre en-tête et implémentation d’une opérations ü L’en-tête décrit les paramètres en entrée et en sortie de l’opération, c’est-à-dire la façon dont on peut utiliser une opération. On parle de spécifications d’une opération. ü Le corps de l’opération est son implémentation. Dans un premier temps, on ne précise que l’en-tête des opérations. Distinction entre paramètres publiques et paramètres privés ü Les paramètres privés sont les attributs de la classe de l’opération. Ils n’apparaissent pas dans l’en-tête. ü Les paramètres publics ne sont pas attributs de la classe. Ils apparaissent dans l’en-tête. Distinction entre opérations publiques et des opérations privées ü Les opérations publiques représentent les fonctionnalités, ou responsabilités, ou services offerts par la classe. Elles disent à quoi sert la classe. Elles permettent de comprendre ce UML – Approche objet - introduction – page 24/51 - Bertrand LIAUDET qu’est la classe. Elles permettent d’utiliser la classe. Les opérations publiques sont visibles par tout le monde. ü Les opérations privées ne sont pas utiles pour le monde extérieur. Ce sont des opérations qui servent aux opérations publiques. Dans un premier temps, on ne précise que les opération publiques. Distinction entre fonctionnel et organique Les 3 distinctions précédentes sont des distinctions entre le fonctionnel et l’organique (le quoi et le comment, l’externe et l’interne, le visible et le caché, le public et le privé). Dans un premier temps, on s’intéresse à l’en-tête des opérations publiques en se limitant aux paramètres formels qui ne sont pas attribut de la classe de l’opération. Formalisme UML Classe avec des attributs de type Classe TÈlÈviseur + + + + + marque alimentation ampli niveauSon etc... : : : : : String Alimentation Ampli int int mettreEnMarche () arrÍ ter () monterSon () : int baisserSon () : int etc... () ü le nom des attributs et des opérations commence par une minuscule. ü Les types simple commencent par une minuscule (int), les types abstraits commencent par une majuscule (Alimentation, String, etc.) ü Les attributs sont privés : « - » devant ü Les opérations sont publiques : « + » devant. Composition à la place des attributs de type classe Le modèle suivant est équivalent au précédent. UML – Approche objet - introduction – page 25/51 - Bertrand LIAUDET TÈlÈviseur - marque : string - etc... : int + etc... () 1 ampli Ampli 1 Alimentation Alimentation - niveauSon : int + monterSon () : int + baisserSon () + mettreEnMarche () + arrÍ ter () UML – Approche objet - introduction – page 26/51 - Bertrand LIAUDET 4. La classe comme interface 2 types d’interface : proposée et utilisée Interface proposée La télécommande du téléviseur est l’interface par laquelle on peut utiliser le téléviseur. C’est l’interface proposée par l’objet. On peut changer d’interface sans changer de téléviseur. L’interface La modélisation objet permet de définir une classe spéciale appelée «interface » et qui permet de définir uniquement l’en-tête des opérations. Les interfaces sont des classes abstraites car aucun objet ne les réalisera. Le corps des opérations n’est pas définit non plus. C’est la classe qui réalise l’interface qui définira le corps des opérations. Dans notre exemple, les usages du téléviseur : allumer, éteindre, monter le son, etc., font partie de son interface. Ils sont réalisée par l’objet téléviseur. La télécommande est un nouvel objet (qui donne lieu à une nouvelle classe) qui va utiliser l’interface des « usages grand public » du téléviseur. Interface utilisée Les prises électriques et les prises câble ou antenne sont les interfaces proposés par les objets « réseau électrique », « réseau de câble » ou « antenne ». Ce sont les interfaces utilisés par le téléviseur pour qu’il puisse fonctionner. Formalisme UML Interface proposée <<interface>> UsagesGrandPublicDuTÈlÈviseur TÈlÈviseur + + + + + marque alimentation ampli niveauSon etc... : : : : : String Alimentation Ampli int int <<use>> <<rÈalise>> + + + + TÈlÈcommande mettreEnMarche () arrÍ ter () monterSon () : int baisserSon () : int mettreEnMarche () arrÍ ter () monterSon () : int baisserSon () : int etc... () La classe « UsagesGrandPublicDuTéléviseur » est stéréotypée « interface ». Le Téléviseur « réalise » l’interface UsagesGrandPublicDuTéléviseur . UML – Approche objet - introduction – page 27/51 - Bertrand LIAUDET Le lien de réalisation est en pointillé. La flèche est un triangle creux (comme pour l’héritage). Le lien peut être stéréotypé « réalise ». La classe « télécommande » utilise l’interface : la télécommande à besoin de l’interface pour fonctionner. autre représentation TÈlÈviseur + + + + + • marque alimentation ampli niveauSon etc... : : : : : String Alimentation Ampli int int <<interface>> UsagesGrandPublicDuTÈlÈviseur TÈlÈcommande <<rÈalise>> + + + + mettreEnMarche () arrÍ ter () monterSon () : int baisserSon () : int 1 mettreEnMarche () arrÍ ter () monterSon () : int baisserSon () : int etc... () Le « use » est en réalité une composition. autre représentation usagesGrandPublic Téléviseur - marque alimentation ampli niveauSon etc... + + + + + mettreEnMarche () arrêter () monterSon () : int baisserSon () : int etc... () Télécommade : String : Alimentation : Ampli : int : int • Le cercle correspond à la classe interface • Le lien entre le téléviseur et le cercle correspond à la réalisation de l’interface. • Le lien avec le demi-cercle correspond à un lien d’utilisation entre classe qui spécifie l’utilisation d’une interface. UML – Approche objet - introduction – page 28/51 - Bertrand LIAUDET Un deuxième usage de l’interface La télévision peut aussi être commandé via son panneau de commandes intégré au poste. Le modèle devient alors : usagesGrandPublic TÈlÈviseur + + + + + marque alimentation ampli niveauSon etc... : : : : : TÈlÈcommande String Alimentation Ampli int int mettreEnMarche () arrÍ ter () monterSon () : int baisserSon () : int etc... () Panneau de commande L’intérêt est donc de bien dissocier, dans la conception, la partie interface utilisateur de la partie objets du système. interface utilisée Si on ajoute les interfaces utilisées par le téléviseur, à savoir un cable, une antenne et une prise électrique, on obtient le modèle suivant : usagesGrandPublic Télécommade Téléviseur - marque alimentation ampli niveauSon etc... : String : Alimentation : Ampli : int : int + + + + + mettreEnMarche () arrêter () monterSon () : int baisserSon () : int etc... () cable antenne prise électrique Conception par les interfaces Pour trouver les interfaces du système, il faut examiner toutes les paires : utilisateur – usage du système. On a intérêt à créer dans un premier temps au moins une classe interface par usage. UML – Approche objet - introduction – page 29/51 - Bertrand LIAUDET Les interfaces se trouvent à un haut niveau d’abstraction. On commence par renseigner les besoins en interfaces utilisateur sans les implémenter. Ces classes seront affinées au fur et à mesure. UML – Approche objet - introduction – page 30/51 - Bertrand LIAUDET 5. Composant logiciel Présentation Modularité, abstraction et encapsulation permettent de construire des composants logiciels réutilisables pouvant aller d’un simple bouton à une application toute entière comme un traitement de texte. Deux types de modularité La modularité dynamique : l’objet ü Un objet est un module cohérent regroupant des données et des opérations. ü Ces modules sont créés dynamiquement et peuvent être passés en paramètre. ü Par l’intermédiaire du nom, on a accès aux opérations. Exemple : un objet polynôme aura deux opérations : calculerRacines( ) et afficherRacines( ) La modularité statique : le package L’architecture logicielle va consister à regrouper les classes dans des modules (les packages). C’est la modularité statique. Abstraction L’abstraction permet d’utiliser un objet général sans se préoccuper des différences et des spécialisations entre différents types de cet objet. Seul le concept général est utilisé ce qui revient à abstraire les différences. Exemple : 3 objets de type voiture : break, berline et coupé, auront chacun des méthodes démarrer( ), couperContact( ), etc. Un utilisateur pourra utiliser un objet voiture sans se préoccuper des différences de nature entre les voitures. Encapsulation L’objet cache la plupart de ses caractéristiques à ses utilisateurs. Les données de l’objet sont cachées. Seules les spécifications (en-tête) des opérations dites publiques sont visibles des utilisateurs. On retrouve là la distinction entre fonctionnel et organique (le quoi et le comment, l’externe et l’interne, le visible et le caché). Les spécifications sont simplifiées car tous les paramètres correspondant à des données de l’objet étant cachés, il n’est pas nécessaire de les préciser. Les données modifiées par les opérations sont gardées dans la mémoire de l’objet. UML – Approche objet - introduction – page 31/51 - Bertrand LIAUDET Exemple : un objet adhérent avec 4 opérations publiques : envoyer(unCourrier : Courrier), afficher(), mettreAJourDossier(), recevoir(unCourrier : Courrier). L’opération afficher permet de consulter les donnée de l’adhérent. L’opération mettreAJourDossier permet de modifier les données de l’adhérent. Exemple On traite le bloc d’alimentation comme un composant à part : <<interface>> <<interface>> I_TÈlÈviseur_Utilisateur I_Alim + + + + + Èteindre () : boolean + allumer () : boolean 1 alim allumer () Èteindre () monterSon () baisserSon () : : : : boolean boolean int int <<rÈalise>> <<rÈalise>> <<use>> TÈlÈviseur Alim - allumÈ : boolean = false + <<Implement>> eteindre () : boolean + <<Implement>> allumer () : boolean - marque : String - ampli : Ampli - niveauSon : int + + + + + <<Implement>> <<Implement>> <<Implement>> <<Implement>> <<Constructor>> allumer () eteindre () monterSon () baisserSon () Televiseur () TÈlÈcommande : : : : boolean boolean int int La classe « Alimentation » réalise deux méthodes d’interface. Le téléviseur accède à la classe Alimentation par son interface qu’il utilise en tant que composant logiciel. Concrètement, le constructeur de la classe « Téléviseur » instancie un objet « Alim » qu’on associe à l’attribut « alim ». Code Java du constructeur : public Televiseur() { alim= (IAlimentation) new Alim(); alim.allumer(); } De ce fait, il existe une dépendance de type « use » entre le téléviseur et l’ampli. C’est le même principe entre la télécommande et l’ampli. On pourrait donc avoir le diagramme de classes suivant : UML – Approche objet - introduction – page 32/51 - Bertrand LIAUDET <<interface>> <<interface>> I_TÈlÈviseur_Utilisateur I_Alim + + + + + Èteindre () : boolean + allumer () : boolean 1 alim allumer () Èteindre () monterSon () baisserSon () : : : : boolean boolean int int <<rÈalise>> <<rÈalise>> <<use>> TÈlÈviseur Alim - allumÈ : boolean - marque : String - ampli : Ampli - niveauSon : int = false + <<Implement>> eteindre () : boolean + <<Implement>> allumer () : boolean + + + + + <<Implement>> <<Implement>> <<Implement>> <<Implement>> <<Constructor>> TÈlÈcommande allumer () eteindre () monterSon () baisserSon () Televiseur () : : : : boolean boolean int int <<use>> <<use>> Toutefois, on évite, en général, de mettre les relations de dépendance autres que celles des interfaces. A noter aussi que les schémas précédents sont équivalents à : <<interface>> <<interface>> I_TÈlÈviseur_Utilisateur I_Alim + + + + + Èteindre () : boolean + allumer () : boolean allumer () Èteindre () monterSon () baisserSon () : : : : boolean boolean int int <<rÈalise>> <<rÈalise>> TÈlÈviseur Alim - allumÈ : boolean = false + <<Implement>> eteindre () : boolean + <<Implement>> allumer () : boolean 1 alim - marque : String - ampli : Ampli - niveauSon : int + + + + + <<Implement>> <<Implement>> <<Implement>> <<Implement>> <<Constructor>> allumer () eteindre () monterSon () baisserSon () Televiseur () <<use>> : : : : boolean boolean int int Toutefois, on préfèrera la première version pour des raisons de lisibilité. UML – Approche objet - introduction – page 33/51 - Bertrand LIAUDET TÈlÈcommande 6. L’objet Définition Un objet est un exemplaire d’une classe. Principes techniques Déclaration Pour pouvoir utiliser un objet, c’est-à-dire utiliser une de ses opérations publiques, il faut le déclarer une variable ayant comme type la classe de l’objet en question. Techniquement, la déclaration d’un objet est toujours la déclaration d’un pointeur sur un objet. La déclaration ne crée pas l’objet mais seulement le pointeur vers un futur objet. Construction On distingue donc entre déclaration et construction de l’objet. La construction s’effectue par l’opérateur « new » qui va allouer dynamiquement un objet et renvoyer l’adresse de cette allocation, adresse qui sera affectée à une variable ayant comme type la classe de l’objet en question. Comme toute variable allouée dynamiquement, l’objet n’a donc pas à proprement parler de nom. Quand on déclare un objet, le nom de la variable est le nom du pointeur qui permet d’accéder à l’objet. Le pointeur pourra référencer un autre objet : on peut donc changer d’objet sans changer de variable. Initialisation Un objet peut être initialisée lors de sa construction, via des opérations particulières appelées « constructeurs ». En conception, la construction-initialisation n’est pas abordée. C’est cependant un élément centrale de la programmation. Lieux de déclaration – construction des objets La déclaration et la construction d’un objet peut se faire à deux endroits différents : ü Au niveau des attributs d’une classe ü Au niveau d’une variable locale d’une opération Provenance des objets d’une méthode Un objet, dans le corps d’une méthode, provient de trois lieux : UML – Approche objet - introduction – page 34/51 - Bertrand LIAUDET ü C’est un attribut de l’objet de la méthode : il a été construit avec l’objet. ü C’est une variable locale à la méthode : il est construit dans la méthode. ü C’est un paramètre formel de la méthode : il a été fournit par la fonction appelante. Toutefois, en dernière analyse, on retombera sur les deux premiers cas. • Ce dernier cas fait que : si un objet d’une classe 1 fait appel à une opération dont un paramètre est un objet d’une classe 2 alors la classe 1 dépend de la classe 2. Syntaxe UML Les objets sont soulignés et placés dans un rectangle. Le nom de l’objet commence par une minuscule. Le nom de la classe commence par un majuscule. Objets nommés : olivier Objets sans noms : : Eleve 7. bertrand : Professeur La communication entre les objets : envoi de message Principe général de l’envoi de message Envoyer un message à un objet c’est utiliser une de ses opérations. Un objet 1 envoi un message à un objet 2 quand une opération de l’objet 1 utilise une opération de l’objet 2. Pour cela, l’objet 2 doit exister dans l’environnement de l’opération appelante de l’objet 1 : • soit c’est une variable locale de l’opération 1, • soit c’est un objet passé en paramètre de l’opération 1, • soit c’est un attribut de l’objet 1. Envoi de message et héritage En programmation objet, la manière d’associer du code à un message est un mécanisme dynamique qui n’est pas établi à la compilation. Autrement dit, l’envoi d’un message ne correspond pas à un débranchement vers une adresse de code prédéfinie comme c’est le cas en programmation procédurale classique. C’est la relation d’héritage entre classes qui permet de gérer ce mécanisme. Syntaxe UML du diagramme de séquence Un expéditeur Un destinataire UML – Approche objet - introduction – page 35/51 - Bertrand LIAUDET Envoi simple retour implicite UML – Approche objet - introduction – page 36/51 - Bertrand LIAUDET 8. Exemple complet : la bibliothèque Cahier des charges On considère l’exemple d’une bibliothèque. On considère 2 usages : l’emprunt de livres et le retour d’un livre. Pour emprunter un ou plusieurs livres, l’adhérent se sert dans les rayonnages, puis donne sa carte au bibliothécaire qui l’identifie. Ensuite, l’adhérent donne ses livres au bibliothécaire qui les identifie. Ensuite, le bibliothécaire redonne la carte et les livres à l’adhérent. L’adhérent ne peut pas emprunter plus de 3 livres en même temps. Les livres ne doivent pas être emprunter plus de 14 jours. En cas de retard d’un livre, l’adhérent ne peut plus emprunter d’autres livres. Pour rendre un livre, n’importe qui donne le livre au bibliothécaire qui l’identifie. Analyse des interfaces Pour trouver les interfaces du système, il faut examiner toutes les paires : utilisateur – usage du système. L’utilisateur, c’est le bibliothécaire. Il y a deux usages : • rendreLivre( ). Pour cela, il suffit d’identifier le livre à rendre. • emprunterLivre( ). Pour cela, il faut commencer par identifier l’adhérent pour ensuite identifier le livre à emprunter. • Ces usages sont des méthodes de la classe Livre. On rend quoi : un livre. On emprunte quoi : un livre. Ces usages caractérisent l’objet livre. • • <<interface>> UsagesAdhÈrents + emprunterLivre (Adherent adhÈrent) : LivreEmprunte + rendreLivre () <<rÈallise>> <<use>> Livre Ecran • - numLivre : int - titre : string - auteur : string + emprunterLivre (Adherent adherent) : LivreEmprunte + rendreLivre () + identifierLivre () Remarque : UML – Approche objet - introduction – page 37/51 - Bertrand LIAUDET Les paramètres des méthodes seront découverts avec l’analyse du diagramme de séquence. UML – Approche objet - introduction – page 38/51 - Bertrand LIAUDET Analyse des écrans On a intérêt à imaginer les écrans pour concrétiser le système : Ecran « enregistrerUnRetour( ) Identifier Livre : OK Info Adhérent Nom Prenom Etc Livres empruntés Id, Titre, auteur, Date emprunt, date retour max, nb jours de retard Id, Titre, auteur, Date emprunt, date retour max, nb jours de retard On saisie l’id du livre et on valide. On récupère les infos sur l’adhérent et les livres en cours d’emprunt. Ecran « enregistrerDesEmprunts( ) Identifier Adhérent : OK Info Adhérent Nom Prenom Etc Livres empruntés Id, Titre, auteur, Date emprunt, date retour max, nb jours de retard Id, Titre, auteur, Date emprunt, date retour max, nb jours de retard Identifier Livre : OK On saisie l’id de l’adhérent et on valide. On récupère les infos de l’adhérent. On saisie l’id du livre et on valide. La liste des emprunts de l’adhérent est mise à jour. UML – Approche objet - introduction – page 39/51 - Bertrand LIAUDET Analyse des scénarios Scénario d’emprunt d’un livre (diagramme de séquence) : Ècran BD BibliothÈcaire ecranDeGestionDesEmprunts lire Id AdhÈrent new (id Adherent) :AdhÈrent identifierAdhÈrent(id AdhÈrent) select adhÈrent infos adhÈrent select emprunts liste des emprunts new :LivreEmpruntÈ ajoutLivreEmpruntÈ(:LivreEmpruntÈ) afficherAdhÈrent( ) lire Id Livre new (id livre) new:LivreEmpruntÈ emprunterLivre(adhÈrent) select livre update emprunts new:LivreEmpruntÈ ajoutLivreEmpruntÈ(new:LivreEmpruntÈ) afficherAdhÈrent( ) delete delete delete Remarques : • On crée un pseudo objet écran qui nous permet de clarifier l’interface avec l’utilisateur, et un pseudo objet « BD » pour clarifier l’interface avec la BD. Ces objet n’apparaîtront pas dans le diagramme de classes. UML – Approche objet - introduction – page 40/51 - Bertrand LIAUDET • Les objets « :Adhérent », « :LivreEmprunté » et « new:LivreEmprunté » sont détruits à la sortie de la méthode « EnregistrerDesEmprunts » • La méthode « identifierAdhérent » pourrait être intégré dans le constructeur de l’adhérent et ne pas être détaillée au niveau du diagramme de séquence. UML – Approche objet - introduction – page 41/51 - Bertrand LIAUDET Diagramme des classes Livre - numLivre : int - titre : string - auteur : string + emprunterLivre (Adherent adherent) : LivreEmprunte + rendreLivre () + identifierLivre () AdhÈrent - numAdhÈrent : int - nom : string LivreEmpruntÈ 3 + ajoutLivreEmpruntÈ (LivreEmprunte livreEmpruntÈ) + afficherAdhÈrent () + identifierAdhÈrent () - dateEmprunt : date - dateRetourAttendue : date - retard : int Remarques : On met 3 pour le nombre de livres empruntés par l’adhérent pour obtenir un tableau 3 livres empruntés dans la table des adhérents. Le livre emprunté est une espèce de livre : il hérite des attributs et des méthodes du lives et porte des attributs supplémentaires. A noter qu’on devrait descendre la méthode : « emprunterLivre » au niveau de la classe « LivreEmprunté » UML – Approche objet - introduction – page 42/51 - Bertrand LIAUDET 9. Diagramme de classes et base de données : les classes « métier ». Classes-métier et classes organiques On distingue entre classe « métier » et classe organique. Les classes-métier sont celles qui correspondent directement au métier de l’application traitée tandis que les classes organiques sont des classes plus techniques. Les classes-métier correspondent reprennent grosso modo le modèle conceptuel des données (le MCD). Elles permettent une première approche du système. Classes-métier et base de données On peut utiliser le MCD ou les tables de la base de données pour commencer à réaliser un diagramme de classes-métier. Relations entre le modèle BD et le modèle objet MEA ADHERENTS NA nom adr tel 0,n EMPRUNTER LIVRES 0,n NL Èditeur datEmp durÈeMax datRet 1,1 correspond ‡ OEUVRES N0 auteur titre 0,n UML UML – Approche objet - introduction – page 43/51 - Bertrand LIAUDET EMPRUNTER OEUVRES + datEmp : java.util.Date + durÈeMax : java.util.Date + datRet : java.util.Date + N0 : int + auteur : java.lang.String + titre : java.lang.String 1..1 ADHERENTS + + + + NA nom adr tel : : : : double java.lang.String java.lang.String java.lang.String 0..* LIVRES 0..* 0..* + NL : int + Èditeur : int Explications de technique UML • Tous les attributs sont « + » c’est-à-dire public. En réalité, ils devraient passer « - » , c’està-dire privés. Il faut donc faire attention aux résultats des traductions automatiques ! • En UML, on ne peut pas mettre d’attributs sur les associations. Les associations non hiérarchiques avec attributs du MEA donnent lieu dans le modèle de BD UML à des classes-associations. • Une classe-association est une association classique à laquelle est raccrochée une classe dont les attributs proviennent de l’association non hiérarchique du MEA. Explications sur la modélisation • Les classes « livres » et « oeuvres » ont été fusionnées. Au niveau de l’application, leur distinction est inutile. • La classe association « emprunter » devient une simple classe : « LivreEmprunté » : ça permet de gérer plus finement les cardinalités et les navigabilités. • Les navigabilités sont limités à « Adhérent » vers « LivreEmprunté » et « LivreEmprunté » vers « Livre ». Cela suffit gérer les usages. • L’association entre « LivreEmprunté » et « Livre » est une composition : on aura un attribut de type « Livre » dans la classe « LivreEmprunté ». • L’association entre « Adhérent » et « LivreEmprunté » est de cardinalité 3 : on aura attribut livreEmrunte qui sera un tableau de 3 « LivreEmprunté ». On n’a besoin que de ça. • On a ajouter la classe « Bibliothécaire » qui porte les méthodes de l’interface. • La classe « Bibliothécaire » utilise la classe « Adhérents » Remarque générale On peut partir d’un MCD pour commencer le diagramme des classes. Toutefois, le diagrammes des classes doit être retravaillé en fonction des usages du système. UML – Approche objet - introduction – page 44/51 - Bertrand LIAUDET UML – Approche objet - introduction – page 45/51 - Bertrand LIAUDET 10. L’affichage et les écrans On peut aussi avoir un modèle qui gère l’affichage au niveau de chaque classe : Fenetre EcranAdhÈrent + afficherAdhÈrent (int numAdhÈrent, string nom) <<use>> AdhÈrent - numAdhÈrent : int - nom : string + ajoutLivreEmpruntÈ (LivreEmprunte livreEmpruntÈ) + afficherAdherent () EcranLivreEmpuntÈ + afficherLivreEmpruntÈ () <<use>> LivreEmpruntÈ - dateEmprunt : date - dateRetourAttendue : date - retard : int + afficherLivreEmpruntÈ () : int 1 Livre - numLivre : int - titre : string - auteur : string Avec un tel modèle, la notion d’interface est toujours utile pour présenter les services rendus par le système, mais ne sert plus à dissocier le calcul de l’interface utilisateur. A noter que dans un diagramme de classes global, on évitera la présentation des fenêtres et des écrans. UML – Approche objet - introduction – page 46/51 - Bertrand LIAUDET 11. La gestion des collections Quand on a des collections (ici le tableau des 3 livres empruntés), il peut y avoir des traitements qui s’appliquent à toute la collection. Dans notre exemple, les adhérents pourrait appliquer des traitement à tous leurs livres empruntés. Par exemple, on pourrait vouloir ajouter une semaine de délai à tous les livres empruntés d’un adhérent Le modèle devient le suivant : AdhÈrent - numAdhÈrent : int - nom : string LivreEmpruntÈ 3 + ajoutLivreEmpruntÈ (LivreEmprunte livreEmpruntÈ) + retarderLesDatesRetour (int nbJours) - dateEmprunt : date - dateRetourAttendue : date - retard : int + retarderDateRetour (int nbJours) 1 Livre - numLivre : int - titre : string - auteur : string L’algorithme de « retarderLesDatesRetour » est Pour i de 1 à 3 LivreEmprunté[i].retarderDateRetour(nbJours) Fin pour Pour généraliser le traitement, c’est-à-dire éviter que la boucle de traitement soit dans la classe appelante « Adhérent », on définit une classe « plurielle » ou « collection » : « LivesEmpuntés ». C’est cette classe qui fera le traitement alors que la classe adhérent ne fera qu’appeler la méthode de la classe plurielle. Ainsi le traitement sera accessible à n’importe quelle autre classe. Le modèle devient le suivant : LivreEmpruntÈ AdhÈrent - numAdhÈrent : int - nom : string - dateEmprunt : date - dateRetourAttendue : date - retard : int + retarderLesDatesRetour (int nbJours) + retarderDateRetour (int nbJours) 1 1 <<use multiple>> Livre LivresEmpruntÈs + retarderDateRetour (int nbjours) + ajoutLivreEmpruntÈ (LivreEmprunte livreEmpruntÈ) - numLivre : int - titre : string - auteur : string UML – Approche objet - introduction – page 47/51 - Bertrand LIAUDET Les itérations sur l’ensemble des livres empruntés ont été encapsulées dans la classe plurielle « LivresEmpruntés ». La méthode « retarderLesDatesRetour » de « LivresEmpruntés » contient la boucle. Algorithme de « retarderLesDatesRetour » : LivresEmpruntés.retarderDateRetour(nbJours) UML – Approche objet - introduction – page 48/51 - Bertrand LIAUDET 12. Les 3 relations fondamentales entre les objets (et les classes) : composition, utilisation, héritage Il y a trois types de relations entre les objets : la composition, l’utilisation et l’héritage. Ces trois relations sont aussi les trois relations fondamentales entre les classe Ces relations génèrent des dépendances entre les objets. La composition Un objet 2 est composant d’un objet 1 si c’est un attribut de l’objet 1. La relation de composition génère une dépendance : l’objet 1 dépend de l’objet 2. TÈlÈviseur - marque : string - etc... : int + etc... () 1 ampli Ampli 1 Alimentation Alimentation - niveauSon : int + monterSon () : int + baisserSon () + mettreEnMarche () + arrÍ ter () L’utilisation (ou dépenndance) Un objet 2 est utilisé par l’objet 1 si il est déclaré localement dans une opération d’un objet 1 ou passé en paramètre formel d’une opération d’un objet 1. La relation d’utilisation génère une dépendance : l’objet 1 dépend de l’objet 2. UML – Approche objet - introduction – page 49/51 - Bertrand LIAUDET BibliothÈcaire + + - enregistrerDesEmprunts () enregistrerUnRetour () identifierAdherent (int numAdherent) identifierLivre (int numLivre) <<use>> : : : : void void Adherent Livre <<use>> Livre AdhÈrent - numAdhÈrent : int - nom : string + ajoutLivreEmpruntÈ (LivreEmprunte livreEmpruntÈ) : void - numLivre : int - titre : string - auteur : string L’héritage Une classe peut hériter des attributs et des opérations d’une autre classe. La classe héritière est appelée sous-classe, la classe dont elle hérite est appelée classe parente. Une classe parente peut à son tour hériter. Si une classe a une seule classe parente, on parle d’héritage simple sinon d’héritage multiple. Héritage d’attributs : l’ensemble des attributs d’un objet d’une classe est constitué de l’ensemble de ses attributs et de l’ensemble des attributs de ses classes parentes. En ce sens, l’héritage est une façon d’organiser les concepts dans un rapport d’espèce à genre : l’espèce (sous-classe) est une sorte du genre (classe parente). Héritage d’opérations : l’ensemble des opérations applicables à un objet est constitué de l’ensemble de ses opérations et de l’ensemble des opérations de ses classes parentes. En ce sens l’héritage est une technique de partage et de réutilisation du code existant. La manière d’associer du code à un message est un mécanisme dynamique qui n’est pas établi à la compilation. L’envoi d’un message ne correspond pas à un débranchement vers une adresse de code prédéfinie comme c’est le cas en programmation procédurale classique. La programmation objet permet de trouver dans la hiérarchie des classes, le code du message à exécuter. L’algorithme qui permet d’associer du code à un message peut donc être vu ainsi : ExecRécursif (message, classe) Si ilExiste (message, classe) Exectuer (message, classe) Return Finsi Si parent (classe) = null Afficher (« erreur ») Return Finsi UML – Approche objet - introduction – page 50/51 - Bertrand LIAUDET ExecRécursif (message, parent (classe) ) Fin Formalisme UML Fenetre EcranAdhÈrent • + afficherAdhÈrent (int numAdhÈrent, string nom) EcranLivreEmpuntÈ + afficherLivreEmpruntÈ () UML – Approche objet - introduction – page 51/51 - Bertrand LIAUDET