Vous êtes sur la page 1sur 27

Conception des

logiciels
-Principes de la Conception-

Résumé du cours
Conception de logiciels
La conception est un processus
de résolution de problèmes dont
l’objectif est d’identifier la
meilleure façon:
• d’implémenter les besoins
Étape cruciale du développement Activité itérative/incrémentale fonctionnels d’un système... La conception propose une architecture de l’application
logiciel: pont entre l’analyse des qui transforme progressivement solution au problème spécifié lors (architecture logicielle et
besoins et l’implémentation. les besoins vers un produit final. • tout en respectant les de l’analyse architecture physique),
contraintes imposées par les
besoins non fonctionnels...
• et en adhérant à des principes
de base menant à un logiciel de
qualité.

description détaillée des


modules, des interfaces Activité Intellectuelle Créativité Expérience. Pas de recettes toutes faites.
utilisateurs, des données.

Mais il existe des méthodes Une bonne conception contribue


Résultat de la phase de conception
(principes & bonnes pratiques) à la qualité du logiciel: fiabilité,
= conception ou « design ».
pouvant être de bons conseils correction, évolutivité, etc.
Quelques principes de conception Qualités
logicielles
Modularité: diviser le système en composants logiques appelés modules. Un module est un composant d’une application, contenant des définitions de en jeu
données et/ou de types de données et/ou de fonctions et constituant un tout cohérent.

Abstraction: identifier pour un ensemble d’éléments les caractéristiques communes avec description générique de l’ensemble considéré : se focaliser
sur l’essentiel, cacher les détails.

Encapsulation: dissocier l’interface contractuelle de la mise en œuvre d’un composant: Associer à un composant une vue externe et une vue interne.

Anticipation des changement: développer un design qui facilite l’ajustement du système aux changements:
• Perfectionnement du système imposé par les nouvelles exigences du client.
• Adaptations imposés par la modification de l’environnement matériel, social, etc.
La bibliothèque contient un ensemble de fonctionnalités
l'API, c'est la liste des fonctionnalités que la librairie contient
Réutilisabilité: Concevoir le design de façon à ce que les différents aspects du système soient utilisables (dans
Un framework différents
“cadre contextes
de travail“) désigne en général un
Généraliser le design autant que possible ensemble de plusieurs bibliothèques ayant des fonctions beaucoup
Simplifier le design autant que possible plus étendues. L’objectif d’un framework est généralement
Ajouter des options aux différents modules de simplifier le travail des développeurs informatiques, en leur
offrant une architecture “prête à l’emploi” et qui leur permette de
ne pas repartir de zéro à chaque nouveau projet.

Réutilisation: Réutiliser autant de composantes que possible: Réutiliser les designs existants permet de tirer profit de l’effort investi par les
concepteurs de composantes réutilisables
Qualité d’une bonne conception

• Il n'existe pas de critère définitif permettant de définir une bonne conception.


• Suivant le type de l'application,
• les besoins non fonctionnels,
• le critère décisif peut être l'efficacité du code produit, sa compacité ou la maintenabilité du
produit, etc.
• Nous retenons la maintenabilité.
• Une bonne conception facilite la maintenance:
• le coût des changements à apporter au système est minimal.
• la conception est plus facile à comprendre
• l'effet des changements est mieux localisé.
• Une conception de qualité apporte à la fois:
• une forte cohésion,
• un faible couplage.
Couplage

Couplage: mesure de l’interdépendance entre deux modules.

Un ensemble de modules est faiblement couplé si les liens de


dépendance (interactions) entre ces modules sont peu
nombreux=>Les systèmes faiblement couplés sont constitués
d'unités indépendantes ou presque indépendantes

Les systèmes fortement couplés ont des interconnexions fortes,


avec des unités de programme dépendantes les unes des autres.
Types de couplage

• Approche procédurale • Couplage en orienté objet


• De contenu: les modules échangent de l'information en lisant et - Couplage entre composants : lorsqu'une classe utilise en tant qu'attribut, une autre
écrivant directement dans leurs espaces de données (variables) classe.
respectifs. Lorsqu’une composante modifie déloyalement les - Couplage d'héritage : si une des deux classes est directement ou indirectement une
données internes d’une autre composante de façon furtive, sous-classe de l'autre.
secrète… - Couplage d'interaction : lorsqu'une classe invoque une ou plusieurs méthodes de
l'autre. Pour détailler ce type de couplage.
• Commun (global) : les modules échangent de l'information via un • Couplage de Données : deux classes présentent un couplage de données, si
ensemble de données (variables) commun. elles échangent des données seulement en paramètres. Ce type de couplage est
le plus recommandé dans les systèmes orientés objet.
• De contrôle: un module appelle une autre en utilisant une variable
• Couplage de structures de données : deux classes présentent un tel couplage,
de contrôle ou une commande contrôlant l’exécution de la
si deux de leurs méthodes respectives se passent comme paramètre une
procédure appelée structure de données entière alors qu'une partie de cette structure aurait suffi.
• De structures de données (d’estampillage) : Il y a couplage de • Couplage de Contrôle : une classe communique avec une méthode d'une
structures de données si un module passe une structure de données autre classe à travers le passage de paramètres qui servent à des fins de
par argument à un autre module. Le module appelé n’a pas besoin contrôle d’exécution.
• Couplage Commun : il signifie que plusieurs méthodes partagent un même
de tous les éléments contenus dans la structure de données.
ensemble de données.
• De données: Il y a couplage de données si un module passe des • Couplage de Contenu : c'est le pire des couplages. Il signifie qu'une méthode
données par argument à un autre module. Le module appelé utilise accède directement à l'implantation d'une méthode appartenant à une autre
toutes les données passées en arguments. classe ou à ses variables d’instances.

 CBO (Coupling between object classes )métrique pour l’orientée


objet:mesure de couplage correspondant au nombre de classes dont
la classe considérée est dépendante
Cohésion

Cohésion= Mesure de la force des relations qui unissent les éléments


fonctionnels à l’intérieur d’un module.
• De façon idéale, un composant devrait implémenter une seule fonction logique ou
une seule entité logique sachant que toutes les parties du composant doivent
contribuer à cette implémentation.
• Si un composant comporte des parties qui ne sont pas directement relatives à sa
fonction logique (par exemple si c'est un groupe d'opérations n'ayant rien à voir,
mais qui sont effectuées en même temps), ce composant n'a qu'un faible degré de
cohésion.
Types de Cohésion
• Approche procédurale • Cohésion en orienté objet
 Cohésion de méthodes: décrit la liaison entre les différentes méthodes d’une
 Cohésion fonctionnelle (la meilleure) : toutes les opérations concourent à la
c l a s s e . les types de cohésion définis dans l’approche procédurale sont utilisés (aléatoire, logique, temporelle,
réalisation de la même tâche: la cohésion« où chaque élément de traitement est
une partie constituante et essentielle pour l'exécution d'une fonction» procédurale, communicationnelle, séquentielle et fonctionnelle).
 Cohésion séquentielle : les opération s'enchaînent. Les sorties d ’une opération  C o h é s i o n d e c l a s s e : décrit la liaison entre les méthodes et les attributs définis à l'intérieur de la classe..
sont les entrées d ’une autre opération (lorsque les méthodes qui manipulent le Les variables d’instance et les méthodes héritées ne sont pas considérés. Types de cohésion (de la plus faible à
même ensemble de données doivent être appelées dans un ordre spécifique.): Pour la plus forte):
un module ayant une cohésion séquentielle « les données de sortie d'un élément de • Séparable: les objets de la classe représentent différentes abstractions de données qui n’ont pas de lien
traitement deviennent les données d'entrée pour le prochain élément» entre eux: Il en existe des attributs non utilisés par les méthodes ou des méthodes qui n’utilisent aucun
 Cohésion communicationnelle : « Un ensemble d'éléments de traitement sont attribut et qui n’appelle aucune autre méthode.
associés de façon communicationnelle [quand] tous les éléments opèrent sur les • Multi-facettes: les objets de la classe représentent différentes abstractions de données qui sont liées
mêmes données d'entrée el/ou génèrent les mêmes données de sorties» entre elles et accessibles par au moins une méthode. Alors que la cohésion séparable peut être détectée
par une analyse syntaxique de la classe, la cohésion multi-facettes nécessite une analyse sémantique.
 Cohésion procédurale: Les éléments d'un module de cohésion procédurale
Effectivement, au moins une méthode accède à une variable d’instance ou invoque une méthode
forment une unité procédurale telle qu'une boucle, un énoncé de décision ou une
appartenant à un concept sémantique distinct.
séquence linéaire d'opérations • Non déléguée: ni séparable, ni multi-facettes mais une méthode utilise une variable d’instance qui
 Cohésion temporelle: «On dit qu'un module est temporellement cohésif si tous ses décrit une composante de la classe et au moins une méthode utilise une variable d’instance décrivant
éléments sont associés en fonction du temps seulement un composant de la classe. La variable d’instance ne décrit pas l'abstraction de données
 Cohésion logique: lorsque les méthodes sont reliées logiquement par un ou représentée par la classe mais seulement un de ses composants.
plusieurs critères communs. • Cachée: ni séparable, ni multi-facettes, ni non déléguée mais il existe une abstraction de données qui est
 Cohésion aléatoire (la pire): les opérations sont dans le même module par cachée. Une cohésion est classifiée cachée si une abstraction de données est cachée dans l'abstraction de
coïncidence: La liaison entre les éléments du module est due à une modularisation données représentées par la classe. Des variables d’instance et des méthodes peuvent être vues comme
aléatoire du système: on écrit du code et ensuite on l'organise en modules. C'est une nouvelle classe à part entière. Il s'agit dans ce cas d'identifier l'abstraction de données et de définir
souvent le cas quand il n'y a aucune conception avant le codage la nouvelle classe.
• Modèle: Elle indique une classe représentant un seul concept sémantique, aucune de ses méthodes ne
peut être déléguée à une classe, et elle ne renferme pas de classes cachées.
 C o h é s i o n d ’ h é r i t a g e : Elle décrit le degré de liaison entre les éléments définis dans la classe et les
éléments hérités. La cohésion d'héritage ne considère pas seulement la super-classe, elle passe à travers tous les
ancêtres de la classe selon l'arbre de hiérarchie
Mesure de la cohésion en orienté objet
• LCOM (lack of cohesion in methods) : métrique orientée objet pour le manque de cohésion.
Méthode 1
• Ii = ensemble des variables d’instance utilisées par la méthode i
• P = ensemble des paires (Ii,Ij) ayant une intersection vide
• Q = ensemble des paires (Ii,Ij) ayant une intersection non vide
• LCOM = max ( |P| - |Q|, 0 )
Méthode 2
• LCOM = graphe biparties.
• Un premier ensemble de nœuds correspond aux différents attributs et un second
ensemble aux différentes méthodes.
• Un attribut est lié à une fonction si celle-ci y accède ou en modifie la valeur.
• Q = Le nombre d’arcs liant les deux parties du graphes
• P = nb_attributs * nb_méthodes – Q.
• LCOM = max ( |P| - |Q|, 0 )
Les principes Solid LE S P R IN CI P E S
S OL I D
SOLID =
introduction

• The Single Responsibility Principle (Responsabilité unique)


• The Open-Closed Principle(Ouvert/Fermé)
• The Liskov Substitution Principle(Substitution de Liskov)
• The Interface Segregation Principle(Séparation des interfaces)
• The Dependency Inversion Principle(Inversion des dépendances)

10
 P r i n c i p e d e re s p o n s a b i l i t é u n i q u e ( S i n g l e re s p o n s a b i l i t y p r i n c i p l e ) : u n e c l a s s e d o i t a v o i r u n e e t u n e s e u l e r a i s o n d e c h a n g e r.
A i n s i , u n e c l a s s e d o i t r e m p l i r u n r ô l e p r é c i s e t i l e s t f a c i l e d e d o n n e r u n n o m à l a c l a s s e , p u is q u e l e s t â c h e s d e l a c l a s s e s o n t
évidentes et restreintes.
 Principe ouvert / fermé (Open-Closed principle): Le s ystème doit s'ouvrir pour l'extension (on peut ajouter de nouvelles
f o n c t i o n n a l i t é s ) e t d o i t r e s t e r f e r m é à l a m o d i f i c a t i o n ( l ' a n c i e n co d e n ’ a p a s n é c e s s a i r e m e n t b e s o i n d ' ê t r e m o d i f i é s u i t e à c e t t e
m o d i f i c a t i o n ) . E n d ' a u t r e s t e r m e s , u n e f o i s q u ’ u n m o d u l e e s t p r ê t p o u r l a p r o d u c t i o n , o n y t o u c h e p l u s j a m a i s . To u t e s l e s
modifications se font à l’extérieur pour que le cœur reste toujours le même.
 P r i n c i p e d e s u b s t i t u t i o n d e L i s k o v ( L i s k o v s u b s t i t u a t io n p r i n c i p l e ) : L e s c l a s s e s d é r i v é e s d o i v e n t ê t r e s u b s t i t u a b l e s à l e u r s c l a s s e s
d e b a s e . I l d o i t ê t r e p o s s i b l e p o u r u n o b j e t d e t y p e T a c c e p t a n t u n e d ép e n d a n c e d e t yp e S , d e p o u vo i r r e m p l a c e r c e t t e d e r n i è r e p a r
u n e d é p e n d a n ce d ' u n t yp e d é r i v é d e S s a n s q u e c e l a e s t l e m o i n d r e i m p a c t s u r l e f o n c t i o n n e m e n t d u c o d e ; A u t r e m e n t d i t , s i S es t u n
s o u s - t yp e d e T, a l o r s t o u t o b j e t d e t yp e T p e u t ê t r e r e m p l a c é p a r u n o b j e t d e t y p e S s a n s a l t é r e r l e s p r o p r i é t é s d é s i r a b l e s d u
p r o g r a m m e c o n c e r n é . L e p r i n c i p e d e s u b s t i t u t i o n d e L i s k o v s ' a p p l i q u e a u x h i é r a r c h i e s d 'h é r i t a g e . I l e s t b i e n a p p l i q u é l o r s q u e t o u t e
c l a s s e d ér i v é e p e u t p r e n d r e l a p l a c e d ' u n e c l a s s e d e b a s e s a n s p r o v o q u e r u n d y s f o n c t i o n n e m e n t d u s ys t è m e . A i n s i , i l f a u t e n v i s a g e r
des abstractions/interfaces de haut niveau avant les implémentations de bas niveau/concrètes.
 P r i n c i p e d e s é g r é g a t i o n d ' i n t e r f a c e s ( I n t e r f a c e s e g r a g a t i o n P r i n c i p l e ) : L a s é g r é g a t i o n s i g n i f i e g a r d e r l e s c h o s e s s ép a r é e s , e t l e
principe de ségrégation des interfaces consiste à séparer les interfaces. Le principe de ségrégation d'interfaces est identique au
p r i n c i p e d e r e s p o n s a b i l i t é u n i q u e d e s c l a s s e s ( S R P ) , m a i s à l a d i f f é r e n c e q u ' i l s ' a p p l i q u e au x i n t e r f a c e s . Le p r i n c i p e d e
responsabilité unique stipule qu'une classe doit avoir une seule responsabilité. Eh bien c'est la même chose pour une interface qui se
d o i t d ' ê t r e l a p l u s p e t i t e p o s s i b l e e t r e p r és e n t e r l ' i m p l é m e n t a t i o n d ' u n e s e u l e t â c h e . N o m b r e u s e s i n t e r f a c e s s p é c i f i q u e s p l u t ô t q u ’ u n e
i n t e r f a c e g é n é r i q u e . I l n e f a u t p a s f o r c e r q u e l q u ’ u n à i m p l é m e n t e r u n e f o n c t i o n d o n t i l n ’ a p as b e s o i n . Av a n t d ’ a j o u t e r u n e n o u v e l l e
méthode à une interface existante, car celle-ci existe déjà, étudier la cohésion de l’interface (elle a un seul objectif clair). Il vaut
m i e u x a v o i r d e u x i n t e r f a c e s p r é s e n t a n t u n n o m b r e l i m i t é d e m é t h o d e s à i m p l é m e n t e r, p l u t ô t q u ' u n e s e u l e i n t e r f a c e d i s p o s a n t d e
nombreuses responsabilités. De toute façon, une même classe peut implémenter plusieurs interfaces
 P r i n c i p e d ’ i n v e r s i o n d e s d é p e n d a n c es ( D e p e n d e n c y I n v e rs i o n P r i n c i p l e ) : c e p r i n c i p e , s t i p u l e q u ' i l f a i l l e p r o g r a m m e r p a r r a p p o r t à
des abstractions plutôt que des implémentations. Les modules de haut niveau ne doivent pas dépendre des modules de bas niveau. Les
d e u x d o i v e n t d é p e n d r e d ' a b s t r a c t i o n s . L e s c l a s s e s d e h a u t n i v e a u n e d e v r a i e n t p a s a vo i r à c h a n g e r à c a u s e d es m o d i f i c a t i o n s
apportées aux classes de bas niveau. Une classe doit dépendre d'interfaces ou de classes abstraites au lieu de classes et de fonctions
concrètes.
LE S P R IN CI P E S
Les principes STUPID S T UP I D

Les mauvaises pratiques STUPID :

• Singleton: Un singleton veille à ce qu'une seule instance d'une classe soit créée, ce qui
peut sembler judicieux (par exemple, la classe connexion). Mais, il devient tentant de
recourir à un singleton pour tout faire ! (contradiction avec la responsabilité unique du
SOLID
• Tight coupling (couplage fort) : il faut réduire le couplage en codant des interfaces
plutôt que des implémentations
• Uuntestability (impossibilité de tester le code): Le couplage fort est la raison principale
qui rend la classe difficile ou impossible à tester
• Premature optimization (optimisation prématurée): il ne faut pas exagérer dans
l’optimisation (qui rend le plus complexe et illisible et surtout difficile à modifier)
• Indescriptive naming (nommage non descriptif) utiliser inconsciemment, aléatoirement
et intuitivement un nommage non descriptif
• Duplication : il faut arrêter de Copier/coller/modifier

12
Série N°4 –
Conception des
logiciels
Questions de réflexion

1. Deux méthodes d'une même classe communiquent par l'intermédiaire d'attributs de


classe (Variables globales).
a. Quel est le type de couplage entre ces deux méthodes ?
Couplage d’interaction global
b. Comment le qualifiez-vous ?
Couplage fort
c. Expliquez comment l’améliorer ?
La communication entre ces méthodes devra se faire à travers les paramètres (en entrée, en sortie, en
entrée/sortie). Si une méthode a besoin d’une valeur pour faire son calcul, elle devra le recevoir en
paramètre et non pas le récupérer à partir d’une variable globale. Si une méthode a besoin de renvoyer un
résultat, elle devra le faire dans ses paramètres de sortie et non pas le stocker dans une variable globale.
Questions de réflexion

2. Une classe A possède une opération op1(in a : integer, in b : string):bool dont le code fait référence à un
objet instance d’une classe B.

A et B sont-elles couplées ? justifiez.

Oui A et B sont couplés. Si la classe B est modifiée, il


faudra vérifier si op1 de la classe A devra être modifiée en
conséquence et même d’autres éléments de la classe A
risquent d’être modifiés.
Exercice n°1: Problème de
cohésion

Soit le code suivant : public static void circonferenceCercle() {


// Lecture du rayon
System.out.print("Entrer le rayon du cercle: ");
double rayon = Keyboard.readDouble();
while(Keyboard.error() || rayon < 0) {
System.err.println("Mauvaise valeur de rayon.");
System.out.print("Entrer le rayon du cercle: ");
rayon = Keyboard.readDouble();
}
// Calcul de la circonférence
double circonference = 2 * Math.PI * rayon;
// Affichage de la circonférence
System.out.println("La circonference est " + circonference);
}

Lire d’abord le rayon au clavier, contrôler la saisie afin de valider le rayon saisi et n’accepter que
1. Que fait ce code ? des valeurs nulles ou positive, calculer la circonférence et l’afficher
2. Analyser et déterminer les problèmes de cohésion de la méthode ci-dessus
3. Proposer une solution pour pallier ces problèmes.
public static void circonferenceCercle() {
// Lecture du rayon
Exercice n°1: Problème de cohésion
System.out.print("Entrer le rayon du cercle: ");
double rayon = Keyboard.readDouble();
Solution : Fractionnement en méthodes plus cohésives et
plus réutilisables
while(Keyboard.error() || rayon < 0) {
// Lit le rayon (positif) d’un cercle au clavier.
System.err.println("Mauvaise valeur de rayon."); public static double lireRayon()
System.out.print("Entrer le rayon du cercle: "); {System.out.print("Entrer le rayon du cercle: ");
rayon = Keyboard.readDouble(); double rayon = Keyboard.readDouble();
} while(Keyboard.error() || rayon < 0)
// Calcul de la circonférence {System.err.println("Mauvaise valeur de rayon.");
double circonference = 2 * Math.PI * rayon; System.out.print("Entrer le rayon du cercle: ");
// Affichage de la circonférence
rayon = Keyboard.readDouble(); }
System.out.println("La circonference est " + circonference);
}
return rayon; }
// Calcule la circonference d’un cercle de rayon donne.
1. Analyser et déterminer les problèmes de cohésion public static double circonferenceCercle(double rayon)
de la méthode ci-dessus {return 2 * Math.PI * rayon;}
● Trois tâches: lecture, calcul et affichage. // Affiche la circonference d’un cercle
● Répétition du code public static void afficheCirconference(double
● Problème de réutilisabilité et de maintenabilité circonference)
{System.out.println("La circonference est " +
2. Proposer une solution pour pallier ces problèmes. circonference);}
Exercice n°2: Problème de
couplage
public class Triangle {
Soit le code suivant : // Colonne courante, ligne courante et nombre total de lignes
public static int colonne, ligne, total;
// Affiche un triangle de nbLignes lignes.
public static void afficheTriangle(int nbLignes) {
total = nbLignes;
for(ligne = 0; ligne < total; ++ligne) {
colonne = 0;
afficheEspaces();
afficheLettres();
System.out.println(); }}
// Affiche les espaces au debut de la ligne courante.
public static void afficheEspaces() {
while(colonne < ligne) {
System.out.print(’ ’);
++colonne; } }
// Affiche les étoiles de la ligne courante.
public static void afficheLettres() {
while(colonne < total) {
System.out.print((char)(’a’ + ligne));
++colonne; } }}
Afficher un triangle rectangle isocèle avec l’angle droit en haut en remplissant la i ème ligne par la i ème
1. Que fait ce code ? lettre de l’alphabet en minuscule
2. Analyser et déterminer les problèmes de couplage dans la classe ci-dessus
3. Proposer une solution pour pallier ces problèmes.
public class Triangle { Solution : Ecrire des méthodes indépendantes
// Colonne courante, ligne courante et nombre total de lignes Eviter autant que possible les variables globales (statiques de classe)

Exercice n°2: : Problème de


public static int colonne, ligne, total; Réécrire afficheEspaces() pour enlever son couplage
// Affiche un triangle de nbLignes lignes. public static void afficheEspaces(int combien)
public static void afficheTriangle(int nbLignes) { { int i;
total = nbLignes;
couplage
for(ligne = 0; ligne < total; ++ligne) {
for(i = 0; i < combien; ++i)
System.out.print(’ ’); }
Réécrire afficheLettres() pour enlever son couplage et Généraliser
colonne = 0; afficheEspaces() pour repeteCaracteres()
afficheEspaces(); public static void repeteCaracteres(char c, int combien){
afficheLettres(); int i;
System.out.println(); }} for(i = 0; i < combien; ++i)
// Affiche les espaces au debut de la ligne courante. System.out.print(c);}
public static void afficheEspaces() { Réécrire afficheTriangle() pour enlever son couplage
while(colonne < ligne) { public static void afficheTriangle(int nbLignes){
System.out.print(’ ’); int ligne;
++colonne; } } for(ligne = 0; ligne < nbLignes; ++ligne)
// Affiche les étoiles de la ligne courante. {repeteCaracteres(’ ’, ligne);
public static void afficheLettres() { repeteCaracteres((char)(’a’ + ligne), nbLignes - ligne);
System.out.println();}}
while(colonne < total) {
System.out.print((char)(’a’ + ligne));
++colonne; } }}
1. Analyser et déterminer les problèmes de couplage dans la classe ci-dessus
● code mal écrit avec des variables globales (statiques de classe) qui nécessite la compréhension du rôle de chaque variable.
● Solution difficilement compréhensible à cause du fort couplage
○ afficheEspaces() et afficheLettres() dépendent des variables globales colonne, ligne et total
○ afficheEspaces() dépend d’afficheTriangle()
○ afficheLettres() dépend d’afficheEspaces() et d’afficheTriangle()

ces méthodes ne sont pas réutilisables (ou presque)

problème de maintenabilité: le changement d’une méthode ou d'une variable affecte le comportement des autres méthodes
Exercice n°3: Les principes
SOLID
1. Un nouveau type d'indemnités de congé doit être ajouté dans un système logiciel pour les ressources humaines. Le codé d’origine doit être
considérablement modifié pour inclure la fonctionnalité. Quel est le principe SOLID enfreint dans cette situation?
Réponse: Le principe “Ouvert/fermé”
Justification: Dans ce cas, vous n'entendez pas la classe, mais vous modifiez le code d'origine. Selon le principe ouvert/fermé, une classe devrait être
ouverte pour l'extension, mais fermée à la modification.

2. Une classe dérivée implémente une méthode redéfinie en lançant une UnsupportedOperationException. Quel est le principe SOLID enfreint dans
cette situation?
Réponse : Le principe de “Substitution de Liskov”
Justification: Dans cette situation, vous êtes confronté à un problème d'héritage. Votre implémentation de bas niveau ne se conforme pas à celles de
haut niveau. Il s'agit d'une violation de la substitution de Liskov.

3. Si une méthode d’une classe présente de trop nombreux cas d’exécution possibles, elle est difficile à tester. Quel est le principe SOLID enfreint
dans cette situation?
Réponse: Le principe de “Responsabilité Unique”
Justification: Si une méthode a de nombreuses options, cela signifie qu'elle effectue plusieurs choses, et ainsi qu'elle a plusieurs responsabilités. Cela
enfreint le principe de responsabilité unique.
4. Quel est le principe SOLID enfreint par le code suivant?

Réponse: Le principe “Ségrégation des interfaces”


Justification: L'interface présente plusieurs responsabilités, ce qui enfreint le principe de ségrégation des interfaces.

5. Pour quelle raison l’extrait du code suivant correspond-il au “U” dans les pratiques STUPID?
1.il est explicite
2.il est impossible de tester
3.il est inutilisable
4.il est impossible de maintenir

Réponse : Le « U » de STUPID signifie “untestability”, impossible à tester. Cet extrait de code est fortement couplé à la classe graphique et ne peut donc pas être
testé indépendamment.
•Analysons les réponses incorrectes
●Réponse 1 : le code est difficile à comprendre, ambigu.
●Réponse 3 : même s'il est trop compliqué, il semble produire un résultat et est donc utilisable.
●Réponse 4 : la gestion à long terme de ce code sera difficile, mais ce n'est pas ce à quoi le « U » fait référence.
6. Quel extrait du code (de a. à d.) complète le code suivant et lui permet de se conformer au principe d’Inversion de dépendances

Réponse: d.
Justification: Analysons les réponses :
❌ Réponse a. : l'élément Motorcycle a
introduit un nouvel ensemble de méthodes.
a. b. Tout élément qui l'utilisera devra changer ses
méthodes afin d'appeler ces nouvelles
fonctions. Ici, la classe de bas niveau pilote la
classe de haut niveau.
❌ Réponse b. : l'élément SelfDrivingCar
dispose des mêmes méthodes, mais n'a pas
inclus « implements Driveable », de sorte qu'il
c. d. ne peut pas être remplacé par un élément
Driveable.
❌ Réponse c. :la classe Driver doit appeler
des méthodes, pour chaque véhicule, en
fonction de la nature de ce dernier. Il n'utilise
pas du tout d'interface pour interagir.
✅Réponse d. : une classe de haut niveau
(Driver) utilise l'interface fournie (Driveable).
7. Lequel des extraits des codes de a. à d. complète correctement le principe Ouvert/fermé de l’extrait du code suivant ?

Réponse: b.
a. b. Justification: Analysons les réponses
incorrectes :
● Réponse a. : Aucune des classes
n'implémente l'interface Rollable, dont
a besoin la classe Game.
● Réponse c. : la classe Game a été
modifiée de façon à seulement utiliser
des objets Die. Elle n'est pas ouverte à
c. d. la modification si vous utilisez un
mécanisme différent.
class Point {
float x; float y;
public :
Point(float nx, float ny) { x=nx; y=ny; }

Exercice float getx() const { return x; }


float gety() const { return y; }
void colorier() {//en utilisant x et y}
void dessiner (){//en utilisant x et y} Point-Forme : Couplage entre composants
};
class Forme {
Forme : Cannevas : Couplage entre composants
Vector<Point> ens_points ;
• Nous nous proposons dans cet Float couleur;
exercice d’étudier en partie, le public :
couplage et la cohésion de la float dist(Point A, Point B) { return sqrt( sqr( A.getx()-B.getx() ) + sqr( A.gety()-B.gety() ) ) ; }
void ajouterForme(Forme forme { // sans l'utilisation de ens_point }
conception d’un logiciel de
void retirerForme(Forme forme) {// sans l'utilisation de ens_point }
dessin. Ce logiciel permet à son void dessiner() {// en utilisant ens_points}
utilisateur de dessiner ou choisir void Colorier{//en utilisant ens_points}
des formes géométriques, de les };
colorier, les placer sur au plus un class Cannevas {
canevas et d’enregistrer le Set <Forme> formes;
résultat dans un format graphique public :
de son choix. void ajouterForme(Forme forme) { formes. insert(forme); }
void retirerForme(Forme forme) { formes. erase(forme); }
• Soit le code c++ suivant :
void dessiner() {
for (std::set<int>::iterator it= formes.begin();it!= formes.end();it++)
forme.dessiner();
}
};
1. Préciser le(s) type(s) de couplage entre les différentes classes.
2. Pour chacune des classes ‘Point’, ‘Forme’ et ‘Cannevas’, précisez si elle est fortement cohésive. Si oui justifiez sinon
proposez les modifications nécessaires afin d’améliorer la cohésion de chaque classe.
class Point {
float x; float y;
public :
Point(float nx, float ny) { x=nx; y=ny; }
float getx() const { return x; }
float gety() const { return y; }
void colorier() {//en utilisant x et y}
void dessiner (){//en utilisant x et y}
};
class Forme {
Vector<Point> ens_points ;
Float couleur;
public :
float dist(Point A, Point B) { return sqrt( sqr( A.getx()-B.getx() ) + sqr( A.gety()-B.gety() ) ) ; }
void ajouterForme(Forme forme { // sans l'utilisation de ens_point }
void retirerForme(Forme forme) {// sans l'utilisation de ens_point }
void dessiner() {// en utilisant ens_points}
void Colorier{//en utilisant ens_points}
};
class Cannevas {
Set <Forme> formes;
public :
void ajouterForme(Forme forme) { formes. insert(forme); }
void retirerForme(Forme forme) { formes. erase(forme); }
void dessiner() {
for (std::set<int>::iterator it= formes.begin();it!= formes.end();it++)
forme.dessiner();
}
};
Nb_attributs= 1
Nb_méthodes=3
Classe Cannevas Q=3
Calcul de LCOM des classes P= 1*3-3= 0

• LCOM = graphe biparties. LCOM= max(0-3, 0)


ajouterforme() LCOM= max(-3, 0)=0
• Un premier ensemble de nœuds correspond aux différents
attributs et un second ensemble aux différentes méthodes. formes retirerforme()
• Un attribut est lié à une fonction si celle-ci y accède ou en
dessiner()
modifie la valeur.
• L’ensemble des arcs correspond à l’ensemble Q.
• P = nb_attributs * nb_méthodes – Q.
• LCOM = max ( |P| - |Q|, 0 )
Attributs Méthodes
Nb_attributs= 2 Nb_attributs= 2
Nb_méthodes=5 Nb_méthodes=5
Q=8
Classe Forme
 Classe Point Q=2
P= 2*5-8= 2 P= 2*5-2= 8

Point() LCOM= max(2-8, 0) dist() LCOM= max(8-2, 0)


Ens_point
LCOM= max(-6, 0)=0 ajouterforme() LCOM= max(6, 0)=6
x Retirerforme()
getx() couleur
gety() dessiner()
Colorier()
colorier()
y
dessiner()

Attributs Méthodes
Attributs Méthodes
26
Classe Point est fortement cohésive car son LCOM=0
Kif kif pour la classe Cannevas (son LCOM=0)
Par contre le Lcom de la classe Forme est supérieur à 0=> Classe non fortement cohésive. Dans ce cas,
nous pouvons déplacer les méthodes dist (qui calcule la distance entre deux points, nous pouvons la
mettre dans la classe Point par exemple), ajouterForme et supprimerForme qui n’utilisent pas l’attribut
ens_points. Nous pouvons aussi déplacer l’attribut couleur qui n’est utilisé dans aucune méthode de la
classe Forme.

Vous aimerez peut-être aussi