jeudi 10 mars 2011

Principe ouvert/fermé

En programmation orientée objet, le principe ouvert/fermé signifie qu'une entité logicielle (classes, modules, fonctions, etc) devrait être ouverte pour extension, mais fermée pour modification. L'idée est que l'on puisse modifier le comportement d'une entité, sans en changer le code source.

Ce principe est particulièrement bien adapté à des environnements de production critiques, où tout changement du code source doit être approuvé par un processus jalonné par des revues de code, des tests unitaires, une phase de qualification, ... En effet, si modifier le code existant implique de détecter d'éventuelles régressions par une batterie de contrôles portant à la fois sur les anciennes et les nouvelles fonctionnalités, au contraire l'étendre peut réduire considérablement l'effort de qualification, puisque ce dernier ne portera que sur les nouveautés.

Depuis son apparition en 1988 dans l'ouvrage Object Oriented Software Construction, l'application de ce principe a largement évolué, et gagné en souplesse.

Principe ouvert/fermé selon Meyer :
On attribue généralement ce concept à Bertrand Meyer, l'auteur de Object Oriented Software Construction :
  • L'implémentation d'une classe en production ne doit pas être modifiée, sauf correction d'anomalies.
  • Ajouter ou changer une fonctionnalité implique de créer une nouvelle classe.
  • La nouvelle classe peut réutiliser le code de la classe existante, par héritage.
  • On est libre d'exposer la nouvelle implémentation par une nouvelle interface ou par l'interface existante.
D'après le principe de Meyer, une implémentation existante peut être réutilisée par héritage, alors que 2 interfaces ne devraient pas hériter l'une de l'autre.

Principe ouvert/fermé par polymorphisme :
Puis, entre 1996 et 2001, plusieurs personnes contribuent à redéfinir le principe ouvert/fermé en tirant profit de l'abstraction et du polymorphisme des langages objet :
  • Le comportement d'une entité peut reposer sur de multiples implémentations différentes.
  • Les implémentations adoptent toutes la même interface, ou héritent de la même classe de base abstraite.
  • L'interface (ou classe abstraite) existante ne peut pas être modifiée.
  • Ajouter ou changer une fonctionnalité implique de créer une nouvelle interface (ou classe abstraite).
  • Les implémentations peuvent être modifiées.
  • Les implémentations peuvent se substituer les unes aux autres par polymorphisme.
D'après le principe par polymorphisme, une interface (ou classe abstraite) existante peut être réutilisée par héritage, alors que 2 implémentations ne devraient pas hériter l'une de l'autre.

Synthèse et comparaison :

OCP selon MeyerOCP par Polymorphisme
Extension par héritage dela classe d'implémentationl'interface existante
Constantes entre 2 évolutionsimplémentation et interfaceinterface seulement
Modification possible pour-implémentations

On constate donc que le principe ouvert/fermé a évolué vers un niveau d'abstraction plus important, ainsi qu'une plus grande flexibilité. Une bonne illustration de ce principe est le design pattern Visiteur de la Guilde des Quatre.

Références :

mercredi 9 mars 2011

SOLID, 5 concepts orientés objet

Dans la conception d'application orientée objet, SOLID est un acronyme introduit par Robert Cecil Martin (alias "Oncle Bob") au début des années 2000. SOLID est la réunion de 5 concepts ou principes en programmation orientée objet. Appliqués ensemble, ils sont susceptibles de permettre de créer des systèmes logiciels plus faciles à maintenir et à faire évoluer. SOLID fait partie des pratiques agiles d'ingénierie logicielle, et peut être un complément puissant à la méthode de pilotage par les tests (Test-Driven Development).


Les 5 principes repris par SOLID sont :
  • S pour SRP, Single Responsibility Principle (principe de la responsabilité unique) :
    Un objet ne devrait avoir qu'une seule responsabilité.
  • O pour OCP, Open/Closed Principle (principe ouvert/fermé) :
    Une entité logicielle, telle que classes, modules, fonctions, etc, devrait être ouverte pour extension, mais fermée pour modification.
  • L pour LSP, Liskov Substitution Principle (principe de substitution de Liskov) :
    Il doit être possible de remplacer un objet par n'importe quelle instance de ses types dérivés, sans que cela affecte le reste de la fonction qui l'utilise.
  • I pour ISP, Interface Segregation Principle (principe de ségrégation des interfaces) :
    Mieux vaut avoir autant d'interfaces que de clients, plutôt qu'une interface à vocation générale.
    Autrement dit, les clients d'une interface ont besoin de connaître de cette interface seulement les méthodes qu'ils utilisent. Inversement, un client ne doit pas dépendre d'une interface dont il n'utilise pas une partie.
  • D pour DIP, Dependency Inversion Principle (principe d'inversion des dépendances) :
    L'inversion des dépendances s'énonce en 2 points :
    1. Des modules haut niveau ne devraient pas dépendre de modules bas niveau et des détails de leur implémentation. Tous devraient dépendre d'abstractions.
    2. Les abstractions ne devraient pas dépendre des détails, mais les détails devraient dépendre des abstractions.
    Exemple : L'Injection de Dépendances (Inversion of Control) est une méthode qui applique ce principe.
Références :