10/06/2024 - 08:54:24
19'06"
Introduction
Cet article se consacre au langage UML pour la création de diagrammes de classes. Il ne traite pas d'UML dans son ensemble, mais se focalise sur la manière de construire ces diagrammes à l'aide de symboles standardisés. L'objectif est d'expliquer la signification de ces symboles et de vous permettre de générer des diagrammes de classe par programmation grâce à une bibliothèque PHP spécialement conçue à cet effet.
L'article est divisé en 3 parties :
- Partie 1: le diagramme de classe et les relations entre classes
- Partie 2: les autres symboles
- Partie 3: exemple complet et code de la librairie
En construction
La librairie trql.uml.class.php
, notre librairie
de classes PHP qui rassemble les symboles nécessaires, est
en construction. Elle sera disponible à la
parution de la partie 3 de l'article.
trql.uml.class.php
et ses exemples
L'article fournira le code de trql.uml.class.php
.
Chaque classe est flanquée d'un exemple DANS LE CODE DE LA CLASSE.
trql.uml.class.php
et ses dépendances
trql.uml.class.php
utilise d'autres classes générales.
Par exemple, le symbole de diagramme de classe utilise 3
rectangles. Le dessin des rectangles est laissé aux soins d'une
classe SVGRect
définie dans
trql.svg.class.php
. Quand j'en aurai fini le code
de toutes les classes nécessaires vous sera fourni.
trql.uml.class.php
et le mode debug
Vous verrez que je peux faire usage du mode
debug
dans l'utilisation de chaque symbole des
classes de trql.uml.class.php
. Il s'agit d'un mode
où les points importants du graphique sont mis en évidence pour
la construction même du symbole : cela aide à visualiser les
points à partir duquel le graphique est construit. Cliquer ici
pour visualiser l'article en mode
debug de telle sorte que vous preniez acte des
points importants de chaque symbole.
Code de la librairie
Le code de la librairie SERA disponible en accès libre sous licence Creative Commons sous licence d'attribution. Donnez-moi du temps pour finaliser les classes les plus urgentes avant de rendre le code disponible.
Les symboles de cet article
Les symboles de cet article sont censés être écrits en PHP générant des SVGs. Chaque symbole est téléchargeable.
Après cette intro, il est temps de passer aux choses sérieuses : le diagramme de classe et ses symboles !
Diagramme de classe
On représente un diagramme de classe 3 rectangles empilés :
Le nom des classes statiques est indiqué en italique.
Les propriétés publiques sont précédées d'un +.
Les propriétés privées sont précédées d'un -.
On peut avoir des guillemets («…») qui entourent des mots-clés (keywords) : ce sont des mots qu'on veut associer à des éléments./ On peut disposer de mots- clefs sur le nom des classes ou sur des attributs/propriétés ou sur des méthodes.
Dans la liste des méthodes d'une classe, celle qui est précédée du mot-clef «constructor» est celle par laquelle on crée une instance de la classe en question.
Les propriétés dérivées sont précédées d'un slash ('/').
Relations
Les classes ont des relations entre elles : elles peuvent s'étendre au travers de la notion d'héritage (inheritance, elles peuvent mutuellement interagir l'une avec l'autre via une sorte d'association et elles peuvent faire partie les unes des autres via association ou composition.
Toutes les raltions s'expriment en UML par une flèche; la flèche en question prend une apparance différénte en fonction de la relation exprimée.
Concepts de relations
Il existe plusieurs types de relations :
- Association : Une association représente une relation entre deux classes. Elle peut être unidirectionnelle ou bidirectionnelle. Par exemple, une classe “Étudiant” peut être associée à une classe “Cours” pour indiquer que chaque étudiant suit un ou plusieurs cours.
- Agrégation : L’agrégation est une forme spécifique d’association où une classe (l’agrégateur) contient d’autres objets (les agrégés). Par exemple, une classe “Université” peut agréger plusieurs objets de type “Département”.
- Composition : La composition est une relation plus forte que l’agrégation. Elle indique qu’un objet est composé de plusieurs autres objets et qu’ils ont une durée de vie liée. Par exemple, une classe “Voiture” peut être composée de plusieurs objets “Roue”.
- Héritage (ou généralisation) : L’héritage permet à une classe (la sous-classe) d’hériter des propriétés et méthodes d’une autre classe (la superclasse). Par exemple, une classe “Étudiant” peut hériter des propriétés de la classe “Personne”.
- Dépendance : Une dépendance existe lorsque le changement d’une classe affecte une autre classe. Par exemple, si une classe “Facture” dépend de la classe “Client”, toute modification dans la classe “Client” peut impacter la classe “Facture”.
Les relations indiquées ci-avant ont aussi une sorte de
quantification (multiplicity). Par exemple
une équipe agile est composée de x membres. Il n'y aurait pas
d'équipe sans les membres et les membres peuvent faire partie de
plusieurs équipes. Ce sont des relations de 0 à n
.
Je reviendrai à cette notion dans le cours de l'article.
Association
ICI, DONNER UN EXEMPLE D'ASSOCIATION
Symbole UML
Code de création du symbole UML (code PHP)
// https://trql.fm/test.uml.association.php $SVG = new SVG(); $SVGWidth = 500; $SVGHeight = 500; $symbol = new SVGUmlAssociation(); $symbol->debug = isset( $_GET['debug'] ); $symbol->x = 15; // x of the line (left) $symbol->y = 100; // y of the line (top) $symbol->w = 300; // width of the line $symbol->aw = 20; // width of the end arrow $symbol->ah = 30; // height of the end arrow $symbol->rotate = 0; // Angle of the whole group starting from the center of the diamond $symbol->cargo = 'association'; $symbol->id = 'SVG_' . $symbol->cargo; $symbol->strokeWidth = 3; $SVG->add( $symbol ); $bg = $_GET['bg'] ?? 'lightyellow'; $SVG->add( $symbol ); echo "<svg id=\"{$symbol->id}\" class=\"uml shadowLight\" xmlns=\"http://www.w3.org/2000/svg\" style=\"background: {$bg};\">\n"; echo $SVG; echo "</svg>\n"; echo "<a href=\"data:image/svg+xml,\" download=\"{$symbol->cargo}.svg\" onclick=\"return copySVG( this,'{$symbol->id}');\">Download</a>\n";
Aggregation
Une agrégation existe quand une classe agrège des variables qui sont d'un type provenant d'autres classes
Symbole UML
On représente une agrégation (aggregation) par un losange et une ligne, le losange partant de la classe qui agrège et allant vers l'objet agrégé.
Un exemple d'agrégation est celui d'une équipe qui ne peut exister que si elle est composée de membres. D'un autre côté le membre d'une équipe peut appartenir à une ou plusieurs équipes. Il y a donc une forme de relation bidirectionnelle entre les deux classes, l'équipe et le membre.
Code de création du symbole UML (code PHP)
// https://trql.fm/test.uml.aggregation.php $SVG = new SVG(); $symbol = new SVGUmlAggregation(); $symbol->debug = isset( $_GET['debug'] ); $symbol->x = 20; // x of the diamond (left) */ $symbol->y = 75; // y of the diamond (top) */ $symbol->w = 50; // width of the diamond */ $symbol->l = 150; // length of the line */ $symbol->rotate = 0; // Angle of the whole group starting from the center of the diamond */ $symbol->cargo = 'aggregation'; $symbol->id = 'SVG_' . $symbol->cargo; $symbol->strokeWidth = 3; $bg = $_GET['bg'] ?? 'lightyellow'; $SVG->add( $symbol ); echo "<svg class=\"uml shadowLight\" xmlns=\"http://www.w3.org/2000/svg\" style=\"background: {$bg};\">\n"; echo $SVG; echo "</svg>\n"; echo "<a href=\"data:image/svg+xml,\" download=\"{$symbol->cargo}.svg\" onclick=\"return copySVG( this,'{$symbol->id}');\">Download</a>\n";
Dependency
Il existe une relation de dépendance lorsque qu'une classe dépend d'une autre de telle sorte qu'une modification apportée à l'une peut affecter l'autre, par exemple lorsqu'une classe accepte une instance d'une autre classe en tant que paramètre d'une méthode.
On représente une dépendance par une ligne formée de tirets terminée par une flèche.
Symbole UML
Code de création du symbole UML (code PHP)
// https://trql.fm/test.uml.dependency.php $SVG = new SVG(); $SVGWidth = 500; $SVGHeight = 500; $symbol = new SVGUmlDependency(); $symbol->debug = isset( $_GET['debug'] ); $symbol->x = 15; // x of the line (left) $symbol->y = 100; // y of the line (top) $symbol->w = 300; // width of the line $symbol->aw = 20; // width of the end arrow $symbol->ah = 30; // height of the end arrow $symbol->rotate = 0; // Angle of the whole group starting from the center of the diamond $symbol->cargo = 'dependency'; $symbol->id = 'SVG_' . $symbol->cargo; $symbol->strokeWidth = 3; $SVG->add( $symbol ); $bg = $_GET['bg'] ?? 'lightyellow'; $SVG->add( $symbol ); echo "<svg id=\"{$symbol->id}\" class=\"uml shadowLight\" xmlns=\"http://www.w3.org/2000/svg\" style=\"background: {$bg};\">\n"; echo $SVG; echo "</svg>\n"; echo "<a href=\"data:image/svg+xml,\" download=\"{$symbol->cargo}.svg\" onclick=\"return copySVG( this,'{$symbol->id}');\">Download</a>\n";
LE REVIEW DE L'ARTICLE S'ARRÊTE ICI; LE RESTE DE L'ARTICLE PEUT ÊTRE INCORRECT!
AUTRES RELATIONS AUSSI!!!
PARLER DE LA QUANTIFICATION (de 0 à n)
Generalization
On représente une généralisation par une ligne pleine terminée par un triangle.
Code de création du symbole UML (code PHP)
// https://trql.fm/test.uml.generalization.php $SVG = new SVG(); $SVGWidth = 500; $SVGHeight = 500; $symbol = new SVGUmlGeneralization(); $symbol->debug = isset( $_GET['debug'] ); $symbol->x = 15; // x of the line (left) $symbol->y = 100; // y of the line (top) $symbol->w = 300; // width of the line $symbol->aw = 20; // width of the end arrow $symbol->ah = 30; // height of the end arrow $symbol->rotate = 0; // Angle of the whole group starting from the center of the diamond $symbol->cargo = 'generalization'; $symbol->id = 'SVG_' . $symbol->cargo; $symbol->strokeWidth = 3; $SVG->add( $symbol ); $bg = $_GET['bg'] ?? 'lightyellow'; $SVG->add( $symbol ); echo "<svg id=\"{$symbol->id}\" class=\"uml shadowLight\" xmlns=\"http://www.w3.org/2000/svg\" style=\"background: {$bg};\">\n"; echo $SVG; echo "</svg>\n"; echo "<a href=\"data:image/svg+xml,\" download=\"{$symbol->cargo}.svg\" onclick=\"return copySVG( this,'{$symbol->id}');\">Download</a>\n";
Composition
Une relation de type composition existe quand une classe est composée d'autres classes, en d'autres termes, la classe n'existerait tout simplment pas sans ses constituants de base, les objets enfants.
On représente une composition par un losange plein et une ligne, le losange partant de la classe qui contient les composants de base vers les composants embarqués dans la classe qui les contient.
Un exemple typique d'objet composé d'autres objets est celui de
notre classe trql.webpage.class.php
. Cet objet ne peut
exister sans des constituants de base comme le corps de la page
(body
) et sans le header de la page
(header
).
Code de création du symbole UML (code PHP)
// https://trql.fm/test.uml.composition.php $SVG = new SVG(); $symbol = new SVGUmlComposition(); $symbol->debug = isset( $_GET['debug'] ); $symbol->x = 20; // x of the diamond (left) */ $symbol->y = 75; // y of the diamond (top) */ $symbol->w = 50; // width of the diamond */ $symbol->l = 150; // length of the line */ $symbol->rotate = 0; // Angle of the whole group starting from the center of the diamond */ $symbol->cargo = 'composition'; $symbol->id = 'SVG_' . $symbol->cargo; $symbol->strokeWidth = 3; $bg = $_GET['bg'] ?? 'lightyellow'; $SVG->add( $symbol ); echo "<svg class=\"uml shadowLight\" xmlns=\"http://www.w3.org/2000/svg\" style=\"background: {$bg};\">\n"; echo $SVG; echo "</svg>\n"; echo "<a href=\"data:image/svg+xml,\" download=\"{$symbol->cargo}.svg\" onclick=\"return copySVG( this,'{$symbol->id}');\">Download</a>\n";
Other
Notes
Les notes peuvent très utiles en UML pour donner des informations complémentaires sur une classe MAIS ATTENTION trop d'infos tuent l'info !
Une note est représentée par un rectangle avec un bord replié :
Lorsqu'une note est liée à un élément spécifique du diagramme, on relie cet élement et la note par une ligne faite de tirets.
Keywords
Templates
Certaines classes peuvent être documentées selon une sorte de template/patron/modèle. Le meilleur exemple qui me vienne en tête sont des classes qui sont des listes : une liste de clients, une liste de fournisseurs, une liste de points de vente, … Bien sûr on traite des objets de nature différente mais au fond, il ne s'agit jamais que de listes !
Une classe template est représentée par les trois boîtes empilées d'un diagramme de classe avec le nom de la classe sur laquelle on opère dans un poetit rectangle composée de tirets. replié :
Le "T" représenté dans le petit rectangle en tirets est le nom de la classe de base.
Derived Attributes/Properties
Les propriétés dérivées sont dérivées d'autres propriétés. Par exemple, le montant d'une facture est une propriété calculée sur la base d'une quantité et d'un prix unitaire. Autre exemple : l'âge d'une personne est calculé en fonction de sa date de naissance et la date du jour.
De telles propriétés sont représentées dans un diagramme de classe en les faisant précéder par un slash ('/').
Constructors
Afin d'identifier LA méthode qui est le constructeur d'une classe il faut la faire précéder du mot-clef «constructor».
Interfaces
Une interface est une classe un peu spéciale qui est une façon d'interagir avec une autre classe, de lui demander de faire quelque chose selon des règles établies.
En UML, une interface est un classifieur qui déclare un ensemble de fonctionnalités publiques cohérentes et des obligations (contrat). Voici les points clés :
- Une interface spécifie un contrat. Toute instance d’un classifieur qui réalise (implémente) l’interface doit respecter ce contrat et fournir les services décrits par celui-ci.
- Les interfaces ne sont pas instanciables directement. Au lieu de cela, une spécification d’interface est mise en œuvre par une instance d’un classifieur instanciable. Ce dernier présente une façade publique conforme à la spécification de l’interface.
- Un classifieur donné peut implémenter plusieurs interfaces, et une interface peut être implémentée par plusieurs classifieurs.
- Les obligations associées à une interface peuvent prendre la forme de contraintes (préconditions, postconditions) ou de spécifications de protocole qui imposent des restrictions d’ordre sur les interactions via l’interface.
En UML, une classe interface s'indique à l'aide du mot-clef «interface» qui précède le nom de la classe.
Voici un exemple d'interface en PHP :
/* ==================================================================================== */ /** {{*interface iContext= {*desc La notion de contexte est assez floue pour l'instant (12-07-20 09:47:19). *} *}} */ /* ==================================================================================== */ interface iContext /*--------------*/ { public function speak(); public function sing(); } /* End of interface iContext ====================================================== */ /* ==================================================================================== */
Voici un exemple d'utilisation d'interface en PHP :
/** {{{*fheader {*file trql.postaladdress.class.php *} {*purpose Mailing address. *} {*author {PYB} *} {*company {COMPANY} *} {*cdate 23-08-20 14:04 *} {*mdate auto *} {*license {RIGHTS} *} {*UTF-8 Quel bel été sous le hêtre *} ------------------------------------------------------------------------------------- Changes History: ------------------------------------------------------------------------------------- {*chist {*mdate 23-08-20 14:04 *} {*author {PYB} *} {*v 8.0.0000 *} {*desc 1) Original creation *} *} *}}} */ /****************************************************************************************/ namespace trql\schema; use \trql\quitus\Mother as Mother; use \trql\quitus\iContext as iContext; use \trql\vaesoli\Vaesoli as Vaesoli; use \trql\schema\Place as Place; use \trql\schema\StructuredValue as StructuredValue; use \trql\contactpoint\ContactPoint as ContactPoint; use \trql\quitus\Mercator as Mercator; use \trql\html\Form as Form; use \trql\html\Fieldset as Fieldset; use \trql\html\Formset as Formset; use \trql\html\Input as Input; use DOMDocument; use DOMXPath; if ( ! defined( 'MOTHER_ABSTRACT_CLASS' ) ) require_once( 'trql.mother.class.php' ); if ( ! defined( 'VAESOLI_CLASS_VERSION' ) ) require_once( 'trql.vaesoli.class.php' ); if ( ! defined( 'PLACE_CLASS_VERSION' ) ) require_once( 'trql.place.class.php' ); if ( ! defined( 'PLACE_CLASS_VERSION' ) ) require_once( 'trql.place.class.php' ); if ( ! defined( 'STRUCTUREDVALUE_CLASS_VERSION' ) ) require_once( 'trql.structuredvalue.class.php' ); if ( ! defined( 'CONTACTPOINT_CLASS_VERSION' ) ) require_once( 'trql.contactpoint.class.php' ); if ( ! defined( 'MERCATOR_CLASS_VERSION' ) ) require_once( 'trql.mercator.class.php' ); if ( ! defined( 'FORM_CLASS_VERSION' ) ) require_once( 'trql.form.class.php' ); if ( ! defined( 'FIELDSET_CLASS_VERSION' ) ) require_once( 'trql.fieldset.class.php' ); if ( ! defined( 'FORMSET_CLASS_VERSION' ) ) require_once( 'trql.formset.class.php' ); if ( ! defined( 'INPUT_CLASS_VERSION' ) ) require_once( 'trql.input.class.php' ); require_once( "trql.iconize.trait.php" ); defined( 'POSTALADDRESS_CLASS_VERSION' ) or define( 'POSTALADDRESS_CLASS_VERSION','0.1' ); /* ==================================================================================== */ /** {{*class PostalAddress= {*desc The mailing address. *} {*credits The whole concept is derived from the fabulous work of Schema.org under the terms of their license: [url]http://schema.org/docs/terms.html[/url] *} {*doc [url]https://schema.org/PostalAddress[/url] *} {*todo [ol] [li]Implement a basic [c]speak/render[/c] by generating microformat tags for a complete address[/li] [/ol] *} *}} */ /* ==================================================================================== */ class PostalAddress extends ContactPoint implements iContext /*--------------------------------------------------------*/ { use \trql\Iconize; /* Defined in trql.iconize.trait.php */ protected $schemaOrg = 'http://schema.org/PostalAddress'; /* {*property $schemaOrg (string) Where the official documentation is maintained *} */ public $addressCountry = null; /* {*property $addressCountry (Country|string) The country. For example, USA. You can also provide the two-letter ISO 3166-1 alpha-2 country code. *} */ public $addressLocality = null; /* {*property $addressLocality (string) The locality in which the street address is, and which is in the region. For example, Mountain View. *} */ public $addressRegion = null; /* {*property $addressRegion (string) The region in which the locality is, and which is in the country. For example, California or another appropriate first-level Administrative division *} */ public $postOfficeBoxNumber = null; /* {*property $postOfficeBoxNumber (string) The post office box number for PO box addresses. *} */ public $postalCode = null; /* {*property $postalCode (string) The postal code. For example, 94043. *} */ public $streetAddress = null; /* {*property $streetAddress (string) The street address. For example, 1600 Amphitheatre Pkwy. *} */ /* === [Properties NOT defined in schema.org] ===================================== */ public $wikidataId = 'Q319608'; /* {*property $wikidataId (string) WikidataId ... pointing to "Collection of information that describes the location of a building, apartment, or other structure address."[br] Wikidata is a free and open knowledge base that can be read and edited by both humans and machines.[br] Wikidata acts as central storage for the structured data of its Wikimedia sister projects including Wikipedia, Wikivoyage, Wiktionary, Wikisource, and others.[br] Wikidata also provides support to many other sites and services beyond just Wikimedia projects! The content of Wikidata is available under a free license, exported using standard formats, and can be interlinked to other open data sets on the linked data web.[br] [url]https://www.wikidata.org/wiki/Wikidata:Main_Page[/url] [url]https://www.wikidata.org/wiki/Special:Statistics[/url] *} */ /* ================================================================================ */ /** {{*__construct( [$szHome] )= Class constructor {*params $szHome (string) Home of the class. Optional. *} {*return (self) The current instance of the class *} {*keywords constructors, destructors *} {*seealso @fnc.__destruct *} *}} */ /* ================================================================================ */ public function __construct( $szHome = null ) /*-----------------------------------------*/ { parent::__construct(); $this->updateSelf( __CLASS__,'/q/common/trql.classes.home/' . basename( __FILE__,'.php' ),$withFamily = false ); return ( $this ); } /* End of PostalAddress.__construct() ========================================= */ /* ================================================================================ */ /* ================================================================================ */ /** {{*speak()= Generate a text about the class itself {*params *} {*return (string) A text representing the object *} *}} */ /* ================================================================================ */ public function speak() : string /*----------------------------*/ { return( '' ); } /* End of PostalAddress.speak() =============================================== */ /* ================================================================================ */ /* ================================================================================ */ /** {{*sing()= Generate a text-to-speech file corresponding to the class itself {*params *} {*return (string) A URL where the text-to-speech file (.mp3) is available *} *}} */ /* ================================================================================ */ public function sing() : string /*---------------------------*/ { return( '' ); } /* End of PostalAddress.sing() ================================================ */ /* ================================================================================ */ } /* End of class PostalAddress ===================================================== */ /* ==================================================================================== */
Les énumérations, ou enums, sont des classes qui fournissent un ensemble fixe de valeurs littérales.
Les énumérations fournissent des attributs (valeurs), mais ne fournissent généralement pas de comportement, de sorte qu'elles peuvent être dessinées sans la section des opérations.
Les énumérations n'ont pas besoin d'indiquer les types d'attributs, puisque tous les attributs sont du type de l'énumération elle-même.
Il n'est pas non plus nécessaire d'indiquer les modificateurs d'accès, car tous les attributs sont implicitement accessibles si l'énumération elle-même est accessible.
En UML, une classe enumeration s'indique à l'aide du mot-clef «enumeration» qui précède le nom de la classe.