Académique Documents
Professionnel Documents
Culture Documents
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é.
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
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
• 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
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.
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)
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?
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; }
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.