1
concepts avancés de POO Concepts SOLID o Principes de bon codage Robert C. Martin «Oncle Bob» Article exposant les concepts SOLID en Mars 1995 SRP The Single Responsibility Principle A class should have one, and only one, reason to change. OCP The Open Closed Principle You should be able to extend a classes behavior, without modifying it. LSP The Liskov Substitution Principle Derived classes must be substitutable for their base classes. ISP The Interface Segregation Principle Make fine grained interfaces that are client specific. DIP The Dependency Inversion Principle Depend on abstractions, not on concretions. 2
SOLID ou STUPID Exemple de code STUPID Singleton (pattern) Tight Coupling Untestability Premature Optimization Indescriptive Naming Duplication Code dupliqué Viole le concept DRY (Don t Repeat Yourself) 3
SOLID ou STUPID Code fonctionnel mais lisibilité Testabilité Extension 4
SOLID ou STUPID Le détail n est pas de la responsabilité de Order. Dépendance d un type concret 5
SRP Principe de responsabilité unique Découpage des responsabilité The Single Responsibility Principle states that every object should have a single responsibility, and that responsibility should be entirely encapsulated by the class. Wikipedia Encapsuler les parties qui changent dans votre code dans une classe Chaque classe a une responsabilité unique souplesse ( moins de couplage) robustesse (changements compartimentées) Cohésion ( compacité et effacité du code) 6
SRP Le questionnement Hum..des fonctionnalités ne sont pas à leurs places 7
SRP Refonte du modèle 8
SRP 9
SRP Séparation des responsabilités Dépendre d une abstraction Prinicipe de séparations des interfaces (SOLID = ISP) 10
SRP Référence vers les objets implémentant le détail des actions à mener Vous noterez l emploi des interfaces (abstraction) Injection de dépendances Mention «peut mieux faire» ici car dépendance des new La validation d un ordre (checkout) entraîne une série d actions invoquées sans en connaitre le détails => principe de délégation de responsabilités 11
En fonction du type d ordre (en ligne, en magasin ou autre) le système de validation de l ordre diffère => Classe virtuelle et checkout abstrait 12
OCP Principe Ouvert-Fermé Code ouvert à l extension et fermé à la modification Open to Extension New behavior can be added in the future Closed to Modification Changes to source or binary code are not required Dr. Bertrand Meyer originated the OCP term in his 1988 book, Object Oriented Software Construction Vous devez pouvoir rajouter une fonctionnalité sans toucher au code existant 13
OCP Boites à outils la composition o Exemple du pattern strategy les design pattern o Pattern Decorateur L abstraction o o Emploi du polymorphisme sur classe abstraite ou interface Associé à la composition Héritage et surcharge o o o Meyers versus Abstraction Une classe fille hérite d une classe de base et surcharge (spécialise) une méthode Approche d une design pattern Template 14
OCP Exemple APRES abstraction AVANT Pour changer de stratégie de codage il faut modifier le code existant Héritage et implémentation Violation OCP Risque de modifications nécessaires en cascades Risque de casser votre code 15
OCP La sérialisation utilise une abstraction (polymorphisme) On ne dépend plus du détails de l implémentation polymorphe Le choix de la stratégie est définie dans le ctor en dur (bofbof) 16
LSP Principe de substitution Concept introduit par Barbara Liskov Les méthodes qui utilisent des objets d une classe doivent pouvoir utiliser des objets dérivés de cette classe sans même le savoir Autrement dit un client doit pouvoir utiliser n importe quelle implémentation (classe de base ou classes héritées) sans changer la cohérence fonctionnelle du système Un code respectant le LSP respectera implicitement OCP LSP permet un outil pour valider une hiérarchie de classes 17
LSP CP Exemple 1 Un plateau de jeu 3D est-il une sorte de Plateau2D Problème de comportement Violation LSP 18
LSP Exemple 2 Les chats mordent et griffes o CODE JAVA Un chat sans griffe EST UN Chat o Modélisation intuitive Héritage! Problème de comportement Violation LSP L héritage vu comme un factorisation de code est une erreur Solution ici: ABSTRACTION +COMPOSITION =pattern STRATEGY 19
LSP Exemple 3 On rajoute la possibilité de récupérer et de stocker les données depuis un cloud ou sur http Problème de comportement => Résolution en changeant la modélisation 20
LSP Exemple 4 Un carré est-il un rectangle? 21
LSP L héritage qui semblait naturel pose un problème fonctionnel. Les «contraintes» d un carré sont plus fortes que celles d un rectangle Pour un rectangle Precondition for Width=w: w > 0 Post-condition for Width=w: width = w height unchanged Pour un carré Precondition for Width=w: w > 0 Post-condition for Width=w width = w ET height=w height unchanged 22
LSP Fermons les yeux sur les péripéties précédentes. Et si nous rajoutions un calcul d aire? Test unitaire 1: OK Test unitaire 2: KO 23
LSP Une solution l'héritage place l'accent sur la classe de base, qui se présente comme une véritable offre de service affichée par chaque sousclasse. Attention à la relation EST UN qui abouti bien souvent à un mauvais choix de modèle du point de vue comportemental 24
ISP Principe de séparation des interfaces This principle deals with the disadvantages of fat interfaces. Classes that have fat interfaces are classes whose interfaces are not cohesive. In other words, the interfaces of the class can be broken up into groups of member functions. Each group serves a different set of clients. Thus some clients use one group of member functions, and other clients use the other groups. - Robert Martin Ne pas forcer ses classes à implanter au travers d interfaces des services qu elles n utiliserons pas Équivalent du SRP mais appliqué à une abstraction 25
ISP ISP à l oeuvre Si votre interface recouvre trop de responsabilités Créer des interfaces plus petites Les classes peuvent choisir d implémenter ces interfaces secondaires L interface principale (FAT) implèmente les interfaces secondaires IEnumerable responsable du parcours d une collection: utilisation foreach OK 26
ISP Exemple 1 Avant ISP La classe est obligée d implémenter PersistDocument => violation ISP et LSP 27
ISP Solution conforme ISP et LSP! 28
DIP L inversion de dépendances High-level modules should not depend on lowlevel modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions - Robert Martin un objectif 29
DIP Le problème 30
DIP La solution Le contrôle des objets a été inversé!. Abstraction + polymorphisme + injection de dépendance 31
DIP En résumé Un changement sur la couche métier impacte toutes les couches => Changements dans le code en cascade La couche métier implémente le contrat imposé par la couche présentation La couche présentation utilise une couche métier particulière en tant que ICoucheMétier (polymorphe). Une nouvelle implémentation de couche métier n impacte pas la présentation! 32
ISP Notre fil rouge abstraction injection implémentation 33
DIP L inversion de contrôle Posséder «c est dépendre de» L inversion du sens de contrôle des objets est un moyen de respecter le principe d inversion des dépendances L injection d une dépendance est une des solutions techniques 34
DIP L injection de dépendances Principe de délégation o Appelé Hollywood principle: «Don t call us; we ll call you» Mise en œuvre selon 3 techniques o Injection via constructeur À la création de l objet on transmet des références vers les objets délégués On s appuie sur une abstraction (polymorphisme d interface par exemple) 35
DIP o Injection via une propriété o Injection d interface 36
DIP Automatiser l injection IoC Container o A la «main» o Framework spécifique pour l injection et la résolution des types Unity, Ninject, Castle Windsor.. Example pour Unity UnityContainer unitycontainer = new UnityContainer(); unitycontainer.registertype<school, School>(); unitycontainer.registertype<iperson, Student>(); var school = unitycontainer.resolve<school>(); school.speak(); unitycontainer.registertype<iperson, Teacher>(); var otherschool = unitycontainer.resolve<school>(); school.speak(); Magique! La résolution de l injection de la dépendance Iperson est gérée en sous main: 2 objets crées: un étudiant et une école 37