Solid Dot Net

download Solid Dot Net

of 15

Transcript of Solid Dot Net

  • 5/25/2018 Solid Dot Net

    1/15

    Bonnes pratiques objet en .net :

    Introduction aux principes SOLID

    par Philippe Vialatte(philippe.developpez.com)

    Date de publication : 21 Octobre 2008

    Dernire mise jour :

    Dans cet article, je vais essayer de vous prsenter les principes SOLID, tels que dcrits

    dans le livre de Robert Martin, Agile Software Development, Principles, Patterns,

    and Practices. On va essayer de voir l'intrt de ces principes, et comment les appliquer,

    de faon (si possible) abordable par tout le monde.

    Commentez cet article :

    http://www.amazon.com/exec/obidos/ASIN/0135974445/qid=1116531248/sr=2-1/ref=pd_bbs_b_2_1/002-3906371-8676026http://www.amazon.com/exec/obidos/ASIN/0135974445/qid=1116531248/sr=2-1/ref=pd_bbs_b_2_1/002-3906371-8676026http://localhost/var/www/apps/conversion/tmp/scratch_6/philippe.developpez.comhttp://www.developpez.com/
  • 5/25/2018 Solid Dot Net

    2/15

    Bonnes pratiques objet en .net : Introduction aux principes SOLID par Philippe Vialatte(philippe.developpez.com)

    - 2 -Copyright 2008 - Philippe Vialatte. Aucune reproduction, mme partielle, ne peut tre faite de ce site et del'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 Ede dommages et intrts. Droits de diffusion permanents accords developpez LLC.

    http://philippe.developpez.com/articles/SOLIDdotNet/

    I - Introduction..............................................................................................................................................................3

    I - A - Cohsion......................................................................................................................................................3

    I - B - Couplage..................................................................................................................................................... 3

    I - C - Encapsulation..............................................................................................................................................3

    II - Responsabilit unique (SRP: Single Responsibility Principle)...............................................................................4

    II - A - Dfinition.....................................................................................................................................................4

    II - B - Comment l'appliquer...................................................................................................................................4II - B.1 - Analyse et regroupement des mthodes........................................................................................... 4

    II - B.2 - Analyse du code................................................................................................................................ 4

    II - C - Exemple......................................................................................................................................................4

    III - Ouvert/ferm (OCP: Open/closed Principle).........................................................................................................7

    III - A - Dfinition....................................................................................................................................................7

    III - B - Comment l'appliquer..................................................................................................................................7

    III - C - Exemple.....................................................................................................................................................8

    IV - Substitution de Liskov (LSP: Liskov Substitution Principle)................................................................................. 9

    IV - A - Dfinition................................................................................................................................................... 9

    IV - B - Comment l'appliquer............................................................................................................................... 10

    IV - C - Exemple.................................................................................................................................................. 10

    V - Sparation des Interfaces (ISP: Interface Segregation Principle).......................................................................11V - A - Dfinition.................................................................................................................................................. 11

    V - B - Comment l'appliquer................................................................................................................................ 12

    V - C - Exemple................................................................................................................................................... 12

    VI - Inversion des dpendances (DIP: Dependency Inversion Principle)................................................................. 12

    VI - A - Dfinition................................................................................................................................................. 12

    VI - B - Comment l'appliquer............................................................................................................................... 13

    VI - C - Exemple.................................................................................................................................................. 13

    VII - Conclusion......................................................................................................................................................... 14

    VIII - Remerciements.................................................................................................................................................15

    http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://localhost/var/www/apps/conversion/tmp/scratch_6/philippe.developpez.comhttp://www.developpez.com/
  • 5/25/2018 Solid Dot Net

    3/15

    Bonnes pratiques objet en .net : Introduction aux principes SOLID par Philippe Vialatte(philippe.developpez.com)

    - 3 -Copyright 2008 - Philippe Vialatte. Aucune reproduction, mme partielle, ne peut tre faite de ce site et del'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 Ede dommages et intrts. Droits de diffusion permanents accords developpez LLC.

    http://philippe.developpez.com/articles/SOLIDdotNet/

    I - Introduction

    Aujourd'hui, une majorit des dveloppeurs dveloppe avec des langages orients objet.

    L'objet est partout, dans tous (ou presque) les langages, et tous les dveloppeurs comprennent intimement ce qu'on

    entend par de la programmation oriente objet...ou pas.

    Aprs avoir pass de nombreuses annes maintenir et dvelopper du code, on se rend malheureusement compte

    que les principes du dveloppement objet sont malheureusement soit ignors, soit mal compris par de nombreux

    dveloppeurs, ce qui rend assez souvent la maintenance des logiciels au mieux malaise, au pire impossible.

    SOLID est l'acronyme de cinq principes de base (Single Responsibility Principle, Open/Closed Principle, Liskov

    Substitution Principle, Interface Segregation Principle et Dependency Inversion Principle) que l'on peut appliquer au

    dveloppement objet.

    On verra dans cet article que ce sont avant tout des principes de bon sens. Aucun ne ncessite une connaissance

    approfondie d'un langage donn. Pour des raisons de got, les exemples seront donns en C#. Ces principes,

    lorsqu'ils sont compris et suivis, permettent d'amliorer la cohsion, de diminuer le couplage, et de favoriser

    l'encapsulation d'un programme orient objet.

    Avant d'attaquer les principes en eux-mmes, on va brivement revoir quoi correspondent ces mtriques.

    I - A - Cohsion

    La cohsion traduit quel point les pices d'un seul composant sont en relation les unes avec les autres. Un module

    est cohsif lorsqu'au haut niveau d'abstraction il ne fait qu'une seule et prcise tche. Plus un module est centr sur

    un seul but, plus il est cohsif.

    I - B - Couplage

    Le couplage est une mtrique qui mesure l'interconnexion des modules. Deux modules sont dit coupls si une

    modification d'un de ces modules demande une modification dans l'autre.

    I - C - Encapsulation

    L'ide derrire l'encapsulation est d'intgrer un objet tous les lments ncessaires son fonctionnement, que ce

    soit des fonctions ou des donnes.

    Le corolaire est qu'un objet devrait (et non pas doit, comme c'est souvent expliqu) masquer la cuisine interne de la

    classe, pour exposer une interface propre, de faon ce que ses clients puissent manipuler l'objet et ses donnes

    sans avoir connaitre le fonctionnement interne de l'objet.

    Pour plus de clart, on verra en quoi chaque principe va jouer sur ces mtriques.

    Comme l'indique le titre de cet article, c'est un article d'introduction. En consquence,

    j'ai essay de rester un niveau abordable, ni trop thorique, ni trop pratique. Certaines

    formulations sont simplifies, et les exemples restent volontairement un niveau

    "scolaire".

    http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://localhost/var/www/apps/conversion/tmp/scratch_6/philippe.developpez.comhttp://www.developpez.com/
  • 5/25/2018 Solid Dot Net

    4/15

    Bonnes pratiques objet en .net : Introduction aux principes SOLID par Philippe Vialatte(philippe.developpez.com)

    - 4 -Copyright 2008 - Philippe Vialatte. Aucune reproduction, mme partielle, ne peut tre faite de ce site et del'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 Ede dommages et intrts. Droits de diffusion permanents accords developpez LLC.

    http://philippe.developpez.com/articles/SOLIDdotNet/

    II - Responsabilit unique (SRP: Single Responsibility Principle)

    II - A - Dfinition

    Ce principe est le plus vieux de ceux tudis ici. Il se base sur les travaux de Tom DeMarco, en 1979, qui le qualifie

    de principe de cohsion. La dfinition que l'on va admettre est:

    "Si une classe a plus d'une responsabilit, alors ces responsabilits deviennent couples.

    Des modifications apportes l'une des responsabilits peuvent porter atteinte ou

    inhiber la capacit de la classe de remplir les autres. Ce genre de couplage amne

    des architectures fragiles qui dysfonctionnent de faon inattendues lorsqu'elles sont

    modifies." -- Robert C. Martin

    Le principe de responsabilit unique, rduit sa plus simple expression, est qu'une classe donne ne doit avoir

    qu'une seule responsabilit, et, par consquent, qu'elle ne doit avoir qu'une seule raison de changer.

    Les avantages de cette approche sont les suivants: Diminution de la complexit du code

    Augmentation de la lisibilit de la classe

    Meilleure encapsulation, et meilleure cohsion, les responsabilits tant regroupes

    II - B - Comment l'appliquer

    Bien que ce principe s'nonce assez facilement, c'est assez souvent le plus compliqu mettre en oeuvre. En effet,

    on a souvent tendance donner trop de responsabilits un objet, et on a parfois du mal identifier, sur un objet

    existant, les responsabilits qui lui choient.

    Une responsabilit peut tre identifie, dans un code existant, des faons suivantes:

    II - B.1 - Analyse et regroupement des mthodes

    Pour une classe de taille importante, il est souvent bnfique de lister toutes les mthodes, et de regrouper celles

    dont le nom ou les actions semblent tre de la mme famille. Si plusieurs groupes apparaissent dans une classe,

    c'est un bon indicateur que la classe doit tre reprise.

    II - B.2 - Analyse du code

    Une autre mthode est de regarder les dpendances externes de la classe.

    La mthode appelle-t-elle directement la base de donnes ? Utilise-t'elle une API spcifique ? Certains membressont-ils appels uniquement par une fonction, ou par un sous-ensemble de fonctions ?

    Si c'est le cas, ce sont peut-tre des responsabilits annexes, dont il faut se dbarrasser...

    II - C - Exemple

    Pour faire simple, on va prendre un mauvais exemple, que l'on va refactoriser.

    On va se baser sur le scnario suivant : notre socit veut concevoir un nouveau systme de suivi de bugs. Pour

    cela, on va implmenter un systme de suivi de Work Items. Aprs un premier jet, on va obtenir le code suivant:

    publicclassWorkItem{

    privatestring_id;

    privatestring_name;

    http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://localhost/var/www/apps/conversion/tmp/scratch_6/philippe.developpez.comhttp://www.developpez.com/
  • 5/25/2018 Solid Dot Net

    5/15

    Bonnes pratiques objet en .net : Introduction aux principes SOLID par Philippe Vialatte(philippe.developpez.com)

    - 5 -Copyright 2008 - Philippe Vialatte. Aucune reproduction, mme partielle, ne peut tre faite de ce site et del'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 Ede dommages et intrts. Droits de diffusion permanents accords developpez LLC.

    http://philippe.developpez.com/articles/SOLIDdotNet/

    // accesseurs...pas la peine de s'appesantir...

    publicvoidSave(){

    SqlConnection cnx =new SqlConnection(ConfigurationManager.ConnectionStrings["database"]); cnx.Open();

    SqlCommand cmd =newSqlCommand();

    cmd.Connection =cnx; cmd.CommandText ="INSERT INTO WorkItem (Id, Name) VALUES ('";

    cmd.CommandText +=_id +"','"+_name +"')";

    cmd.ExecuteNonQuery();

    cnx.Close();

    }

    publicvoidGetById(stringid){

    SqlConnection cnx =new SqlConnection(ConfigurationManager.ConnectionStrings["database"]);

    cnx.Open();

    SqlCommand cmd =newSqlCommand();

    cmd.Connection =cnx;

    cmd.CommandText ="SELECT Id, Name FROM WorkItem where Id = '"+id +"'";

    SqlDataReader dr =command.ExecuteReader();

    if(dr.Read()){

    _id =dr["id"].ToString();_name =dr["name"].ToString();

    }else{

    returnnull;

    } }

    }

    Ce fonctionnement correspond plus ou moins un pattern d'architecture, le pattern

    ActiveRecord. Il n'est pas mauvais en soi, mais dans le cadre du principe SRP, pose

    quelques problmes. A chacun de peser le pour et le contre de chaque approche...

    En termes de responsabilits, cette classe a les responsabilits

    http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://fr.wikipedia.org/wiki/Active_record_(patron_de_conception)http://philippe.developpez.com/articles/SOLIDdotNet/http://localhost/var/www/apps/conversion/tmp/scratch_6/philippe.developpez.comhttp://www.developpez.com/
  • 5/25/2018 Solid Dot Net

    6/15

    Bonnes pratiques objet en .net : Introduction aux principes SOLID par Philippe Vialatte(philippe.developpez.com)

    - 6 -Copyright 2008 - Philippe Vialatte. Aucune reproduction, mme partielle, ne peut tre faite de ce site et del'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 Ede dommages et intrts. Droits de diffusion permanents accords developpez LLC.

    http://philippe.developpez.com/articles/SOLIDdotNet/

    de crer les objets

    de stocker les donnes de l'objet

    et de grer la persistance des objets.

    (On va passer sur le couplage fort entre la structure de la base et de l'objet, sur les risques d'injection, sur la rptition

    du code pour grer les connexions, etc...)

    Apres refactorisation, on va obtenir trois objets, une Factory, un gestionnaire d'accs aux donnes, et un objet de

    transport de donnes.

    publicclassWorkItem{

    privatestring_id; privatestring_name;

    // accesseurs...pas la peine de s'appesantir...

    publicWorkItem(DataRow dr){

    _id =dr["id"].ToString();

    _name =dr["name"].ToString();}

    }publicclassWorkItemFactory{

    publicvoidSave(WorkItem item){

    WorkItemDataAccess.Save(item.Id,item.Name); }

    publicWorkItem GetWorkItemById(stringid){

    Datarow dr = WorkItemDataAccess.GetById(id);

    if(dr ==null){ returnnull;

    }

    returnnewWorkItem(dr);

    }

    }

    publicstaticclassWorkItemDataAccess{

    publicstaticvoidSave(stringid,stringname){ /// requetes sql

    }

    publicstaticDataRow GetById(stringid){

    SqlConnection cnx =new SqlConnection(ConfigurationManager.ConnectionStrings["database"]);

    cnx.Open();

    SqlCommand cmd =newSqlCommand();

    cmd.Connection =cnx; cmd.CommandText ="SELECT Id, Name FROM WorkItem where Id = '"+id +"'";

    DataTable dt =newDataTable();

    using(SqlDataAdapter da =newSqlDataAdapter(cmd)) { da.Fill(dt);

    }

    returndt.Rows.Count ==0?null:dt.Rows[0]; }

    }

    Suite a cette factorisation, les responsabilits de nos trois classes sont beaucoup plus videntes, la classe d'accs

    aux donnes ne traite plus que des donnes, l'objet possde des mthodes pour manipuler ses propres donnes, et

    la factory a la responsabilit de faire travailler ensemble la classe d'accs aux donnes et l'objet...

    La partie mtier est un peu mince, mais on va essayer de l'toffer plus tard.

    http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://localhost/var/www/apps/conversion/tmp/scratch_6/philippe.developpez.comhttp://www.developpez.com/
  • 5/25/2018 Solid Dot Net

    7/15

    Bonnes pratiques objet en .net : Introduction aux principes SOLID par Philippe Vialatte(philippe.developpez.com)

    - 7 -Copyright 2008 - Philippe Vialatte. Aucune reproduction, mme partielle, ne peut tre faite de ce site et del'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 Ede dommages et intrts. Droits de diffusion permanents accords developpez LLC.

    http://philippe.developpez.com/articles/SOLIDdotNet/

    Une notion garder l'esprit est qu'il ne faut pas aller trop loin dans la sparation des responsabilits, au risque de

    tomber dans un excs inverse et se retrouver avec un domaine anmique.

    Un refactoring supplmentaire (et valide) pourrait faire intervenir un nouvel objet CommonDataAccess, qui serait

    appel par les classes d'accs aux donnes

    III - Ouvert/ferm (OCP: Open/closed Principle)

    III - A - Dfinition

    Le principe Ouvert/ferm est, tout comme la substitution de Liskov, issu d'un article datant d'une vingtaine d'annes

    (1988). Sa formulation initiale est la suivante:

    Les entits logicielles (classes, modules, fonctions, etc.) doivent tre ouvertes pour

    l'extension, mais fermes la modification. --Bertrand Meyer

    L'ide originale de Meyer tait qu'en fait, une classe logicielle tait un package de donnes, qui ne devait, une fois

    implment, ne plus tre modifie que pour corriger une erreur. Toute nouvelle fonctionnalit ne devrait, selon lui,pouvoir tre rajout qu'en ajoutant une nouvelle classe, laquelle pouvait ventuellement hriter de la classe d'origine.

    De nos jours, lorsque l'on parle de ce principe, le sens que l'on lui donne en gnral est celui repris dans un article

    de 1996 par Robert Martin. La dfinition tendue qui en est donne est la suivante:

    "Les modules qui se conforment au principe ouvert/ferme ont deux attributs principaux.

    1 - Ils sont "ouverts pour l'extension". Cela signifie que le comportement du module peut

    tre tendu, que l'on peut faire se comporter ce module de faons nouvelles et diffrentes

    si les exigences de l'application sont modifies, ou pour remplir les besoins d'une autre

    application.

    2 - Ils sont "Ferms la modification". Le code source d'un tel module ne peut pas tre

    modifi. Personne n'est autoris y apporter des modifications."

    --Robert C. Martin

    Le but de ce principe est donc de tendre, non plus vers des objets immuables, mais vers des objets auxquels les

    clients pourront ajouter de nouveaux comportements sans en modifier la mcanique interne.

    La diffrence fondamentale entre les deux approches est que, dans un cas, on va utiliser un hritage

    d'implmentation, alors que dans l'autre, on va se baser sur des contrats.

    Pour quelles raisons voudrait-on pouvoir mettre notre programme en conformit avec ce principe ?

    Plus de flexibilit par rapport aux volutions

    Diminution du couplage

    III - B - Comment l'appliquer

    Deux possibilits nous sont donnes, la premire tant de chercher identifier une fonction ou une mthode dont

    le comportement est susceptible d'tre fortement impact par une modification ultrieure. Malheureusement, on va

    plus souvent qu' notre tour tre surpris par les demandes de nos clients. La seconde mthode, plus agile, est de

    conserver un design simple, et, lorsque l'on arrive aux limites de ce design, d'en changer...

    On va donc, le plus souvent, commencer par le code le plus simple pouvant fonctionner, et, lorsque l'on rencontre

    une exception nous obligeant modifier la classe pour l'tendre, s'assurer qu'une modification ultrieure de mme

    type ne nous forcera pas modifier de nouveau notre design. Evidemment, avec l'exprience, on est souvent plus

    mme de sentir quelles portions du programme sont plus mme d'tre modifies, mais c'est un pari que l'on fait.

    http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://localhost/var/www/apps/conversion/tmp/scratch_6/philippe.developpez.comhttp://www.developpez.com/
  • 5/25/2018 Solid Dot Net

    8/15

    Bonnes pratiques objet en .net : Introduction aux principes SOLID par Philippe Vialatte(philippe.developpez.com)

    - 8 -Copyright 2008 - Philippe Vialatte. Aucune reproduction, mme partielle, ne peut tre faite de ce site et del'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 Ede dommages et intrts. Droits de diffusion permanents accords developpez LLC.

    http://philippe.developpez.com/articles/SOLIDdotNet/

    Comme rgles de bonne conduite, on peut essayer d'une part de ne pas dpendre du type d'un objet pour choisir

    un chemin de traitement. Cela se rapproche du principe LSP, que l'on va voir plus bas. D'autre part, on peut limiter

    l'hritage, en y prfrant la composition.

    Si vous vous intressez un petit peu aux design patterns, vous devez certainement avoir dj t expos ce

    principe...

    En effet, un certain nombre de design patterns sont une mise en pratique de ce principe. Par exemple, le DP

    Dcorateurpermet de rajouter un objet de nouvelles fonctionnalits sans modifier son code, par dcoration, le

    DP Visiteurpermet d'tendre les capacits de la collection parcourue sans modifier l'implmentation des objets

    manipuls, etc...

    III - C - Exemple

    On va reprendre notre exemple prcdent de Work Item.

    Aprs une itration, on va avoir une nouvelle demande de notre client (interne, mais client quand mme), savoir qu'il

    veut pouvoir grer plusieurs types de work items. En effet, certains vont matrialiser des tches pour le dpartementinformatique, d'autres, des tches pour le dpartement finance, marketing, ou gestion. Notre premier reflexe va tre

    le suivant:

    publicclassWorkItem{

    privatestring_id;privatestring_name;

    }

    publicclassITWorkItem :WorkItem{

    publicvoidManageITWorkItem(){ // execute des actions relatives au departement informatique

    }

    }

    publicclassFinanceWorkItem :WorkItem{ publicvoidManageFinanceWorkItem(){

    // execute des actions relatives au departement finances

    }

    }publicclassMarketingWorkItem :WorkItem{

    publicvoidManageMarketingWorkItem(){

    // execute des actions relatives au departement marketing

    }

    }

    Tout cela semble marcher. Seulement, que se passe-t-il lorsque l'on veut traiter un ensemble de Work Items ?

    publicRunAllWorkItems(Listitems){

    foreach(WorkItem item initems){

    if(item isITWorkItem){ item.ManageITWorkItem();

    }elseif(item isFinanceWorkItem){

    item.ManageFinanceWorkItem();

    }elseif(item isMarketingWorkItem){ item.ManageMarketingWorkItem();

    }

    }

    }

    On se retrouve avec une implmentation fragile, qui va ncessiter, caque cration d'un nouveau type de Work Item,

    la modification de la fonction RunAllWorkItems, et de toutes les fonctions qui se basent sur le type des Work Items.

    http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://pcaboche.developpez.com/article/design-patterns/programmation-modulaire/?page=page_5http://pcaboche.developpez.com/article/design-patterns/programmation-modulaire/?page=page_2#L1.2http://pcaboche.developpez.com/article/design-patterns/programmation-modulaire/?page=page_5http://pcaboche.developpez.com/article/design-patterns/programmation-modulaire/?page=page_2#L1.2http://philippe.developpez.com/articles/SOLIDdotNet/http://localhost/var/www/apps/conversion/tmp/scratch_6/philippe.developpez.comhttp://www.developpez.com/
  • 5/25/2018 Solid Dot Net

    9/15

    Bonnes pratiques objet en .net : Introduction aux principes SOLID par Philippe Vialatte(philippe.developpez.com)

    - 9 -Copyright 2008 - Philippe Vialatte. Aucune reproduction, mme partielle, ne peut tre faite de ce site et del'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 Ede dommages et intrts. Droits de diffusion permanents accords developpez LLC.

    http://philippe.developpez.com/articles/SOLIDdotNet/

    Une solution conforme OCP serait d'ajouter une interface IWorkItem, et de lui ajouter une fonction ManageWorkItem,

    ManageWorkItem devenant le contrat que chaque classe implmentant IWorkItem devra remplir.

    publicinterfaceIWorkItem {

    voidManageWorkItem();

    }

    publicclassWorkItem {

    privatestring_id;privatestring_name;

    //on saute les accesseurs...

    }

    publicclassITWorkItem :WorkItem,IWorkItem{ publicvoidManageWorkItem(){

    // execute des actions relatives au departement informatique

    }

    }publicclassFinanceWorkItem :WorkItem,IWorkItem{

    publicvoidManageWorkItem(){

    // execute des actions relatives au departement finances

    }

    }

    publicclassMarketingWorkItem :WorkItem,IWorkItem{ publicvoidManageWorkItem(){

    // execute des actions relatives au departement marketing

    }}

    ......

    publicRunAllWorkItems(Listitems){

    foreach(IWorkItem item initems){

    item.ManageWorkItem();

    }}

    De cette faon, on pourra ajouter de nouveaux types de comportement (de nouveaux Work Items) sans avoir

    modifier la fonction RunAllWorkItems. On peut donc l'tendre sans avoir la modifier.

    IV - Substitution de Liskov (LSP: Liskov Substitution Principle)

    IV - A - Dfinition

    La substitution de Liskov, telle que dfinie par Barbara Liskov et Jeannette Wing, s'nonce ainsi :

    Ce que l'on veut est vrifier le proprit de substitution suivante:

    Si pour chaque objet o1 de type S il existe un objet o2 de type T tel que pour tout

    programme P dfini en termes de T, le comportement de P est inchang quand onsubstitue o1 o2, alors S est un sous-type de T

    A cette dfinition fonctionnelle lgrement alambique, je prfre, une fois de plus, la dfinition simplifie donne

    par Robert Martin:

    Les sous-types doivent tre remplaables par leur type de base.

    Plus simple, non ;) ?

    La, je vais en voir un ou deux (ou plus) dire: "Oui, mais partir du moment o ma classe S hrite de ma classe T",

    je dois pouvoir caster S en T et l a va marcher...

    Justement, non...Le but de ce principe est exactement de pouvoir utiliser une mthode sans que cette mthode ait connaitre la

    hirarchie des classes utilises dans l'application, ce qui veut dire:

    http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://localhost/var/www/apps/conversion/tmp/scratch_6/philippe.developpez.comhttp://www.developpez.com/
  • 5/25/2018 Solid Dot Net

    10/15

    Bonnes pratiques objet en .net : Introduction aux principes SOLID par Philippe Vialatte(philippe.developpez.com)

    - 10 -Copyright 2008 - Philippe Vialatte. Aucune reproduction, mme partielle, ne peut tre faite de ce site et del'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 Ede dommages et intrts. Droits de diffusion permanents accords developpez LLC.

    http://philippe.developpez.com/articles/SOLIDdotNet/

    pas de cast

    pas de as

    pas de is

    et surtout pas d'introspection/rflexion

    En effet, si on vrifie le type des objets, on va violer non seulement LSP, mais aussi OCP, il suffit de voir l'exemple

    prcdent de violation d'OCP, qui tait une violation flagrante de LSP. L'inverse ne se vrifie pas, on peut tout faitne pas respecter OCP (l'exemple canonique tant de vouloir ajouter une routine de tri nos objets, ce qui demande

    gnralement de modifier les classes...), et rester en conformit avec LSP.

    Ce principe apporte:

    Augmentation de l'encapsulation

    Diminution du couplage. En effet, LSP permet de contrler le couplage entre les descendants d'une classe et

    les clients de cette classe.

    IV - B - Comment l'appliquer

    Pour dtecter le non respect de ce principe, on va se poser la question de savoir si on peut, sans dommage, remplacerla classe en cours par une interface d'un niveau suprieur.

    Le problme auquel on va se heurter est que, pour valider que le principe LSP est respect, il faut le valider pout

    tous les clients de notre arborescence de classe. L'exemple canonique est le suivant: Si une classe Carr hrite de

    Rectangle, un client manipulant exclusivement des rectangles risque de vouloir affecter une largeur et une hauteur

    diffrentes un carr. Soit le carr sera inconsistant (hauteur et largeur diffrentes), soit la fonction de surface sera

    inconsistante (le client attendant une surface de H*L, et recevant H*H ou L*L).

    Ce principe nous invite revoir la notion d'hritage, dans le sens ou il dfinit la notion d'hritage comme celui du

    comportementqu'un client peut attendre d'un objet. Dans ce cas, on voit qu'en termes de dveloppement objet, un

    carr n'est pas un rectangle, car leurs comportements diffrent pour un client donn.

    IV - C - Exemple

    En dehors de l'utilisation d'un dterminant de type (is, as, rflexion), on va violer ce principe si un descendant modifie le

    comportement de la classe parente de faon a ce que le seul moyen, pour le programme, de fonctionner correctement,

    est de connaitre le type concret de l'objet.

    Pour continuer sur notre lance, on va redfinir la mthode ToString de nos Work Items.

    Pour cela, on va dfinir, au niveau de notre classe WorkItem, une fonction Tostring, qui va renvoyer l'id et le nom

    d'un work item.

    publicclassWorkItem { privatestring_id;

    privatestring_name;

    //on saute les accesseurs...

    publicoverridestringToString(){ // renvoie

    return"id : "+_id +" - name : "+_name;

    }

    }

    Une violation du principe LSP serait d'avoir, au niveau des FinanceWorkItem, par exemple, un override de ToString

    dans ce gout-la:

    publicoverridestringToString(){

    http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://localhost/var/www/apps/conversion/tmp/scratch_6/philippe.developpez.comhttp://www.developpez.com/
  • 5/25/2018 Solid Dot Net

    11/15

    Bonnes pratiques objet en .net : Introduction aux principes SOLID par Philippe Vialatte(philippe.developpez.com)

    - 11 -Copyright 2008 - Philippe Vialatte. Aucune reproduction, mme partielle, ne peut tre faite de ce site et del'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 Ede dommages et intrts. Droits de diffusion permanents accords developpez LLC.

    http://philippe.developpez.com/articles/SOLIDdotNet/

    thrownewException("Pas de ToString, Merci !");}

    (Je sais, c'est moyennement utile, mais c'est pour l'exemple).

    Inversement, mon avis, LSP ne doit pas forcer les descendants d'une classe conserver le mme comportement

    mtier.

    Par exemple, si dans mes FinanceWorkItem, je fais:

    publicoverridestringToString(){

    return"id : "+_id +" name : "+_name;

    }

    Et qu'un de mes clients utilise une fonction de manipulation de chaine de caractres pour rcuprer le nom du Work

    Item, comme :

    stringname =workItem.ToString().Split('-')[1].Substring(8);

    La nouvelle version provoquera une exception chez le client, mais ne sera pas une violation de LSP, le comportement

    restant le mme (on retourne une reprsentation de l'objet sous forme de chane), mais le contenu retourn change

    pour correspondre a une implmentation spcifique.

    V - Sparation des Interfaces (ISP: Interface Segregation Principle)

    V - A - Dfinition

    Pour une fois, ce principe se passe d'une dfinition formelle, ce qui y ressemble le plus tant la dfinition suivante:

    Les clients d'une entit logicielle ne doivent pas avoir dpendre d'une interface qu'ils

    n'utilisent pas.

    Le premier effet d'avoir une interface trop complique va se ressentir assez vite. En effet, toute classe implmentant

    une interface doit implmenter chacune de ses fonctions. On va donc trs vite se retrouver avec une confusion sur

    le rle des sous classes.

    Dans le framework .net (on pourrait certainement trouver des exemples en Java et C++), de nombreuses classes se

    conforment ce principe. Par exemple, la classe gnrique List va implmenter toutes les interfaces suivantes:

    IList ICollection

    IEnumerable

    IList

    ICollection

    IEnumerable

    Les risques d'avoir des interfaces trop compliques ne sont pas toujours vidents. En fait, ils reviennent au poids

    que l'on compte mettre sur les clients de l'interface. En effet, de faon gnrale, plus une interface est complique,

    plus l'abstraction qu'elle prsente est vaste, plus elle est susceptible d'voluer avec le temps. Chaque volution de

    l'interface va entrainer une livraison ou une modification de l'ensemble des clients.

    En consquence, si l'interface doit changer pour un client A qui utilise la fonction A, cela va aussi impacter le clientB, qui n'utilise pas la fonction A, mais qui dpends de la mme interface

    http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://localhost/var/www/apps/conversion/tmp/scratch_6/philippe.developpez.comhttp://www.developpez.com/
  • 5/25/2018 Solid Dot Net

    12/15

    Bonnes pratiques objet en .net : Introduction aux principes SOLID par Philippe Vialatte(philippe.developpez.com)

    - 12 -Copyright 2008 - Philippe Vialatte. Aucune reproduction, mme partielle, ne peut tre faite de ce site et del'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 Ede dommages et intrts. Droits de diffusion permanents accords developpez LLC.

    http://philippe.developpez.com/articles/SOLIDdotNet/

    Ce principe apporte principalement une diminution du couplage entre les classes (les classes ne dpendant plus les

    unes des autres). L'autre avantage d'ISP est queles clients augmentent en robustesse.

    V - B - Comment l'appliquer

    Appliquer ISP est assez simple dans la thorie. En fait, on va revenir plus ou moins la mme dmarche que pourSRP. On va runir les groupes "fonctionnels" des mthodes de la classe dans des Interfaces spares. L'ide tant

    de favoriser le dcoupage de faon ce que des clients se conformant SRP n'aient pas dpendre de plusieurs

    interfaces.

    V - C - Exemple

    Dans nos exemples de Work Items, on va devoir grer des Work Items pour lesquels il existe une deadline. Nos Work

    Items dpendant tous de IWorkItem, on va directement ajouter Les informations de gestion de deadline au niveau

    de IWorkItem et de WorkItem.

    Apres un petit brainstorming, on fait une mise jour de nos classes, et on obtient le code suivant:

    publicinterfaceIWorkItem {

    ...

    boolIsDeadLineExceeded();

    }publicclassWorkItem {

    privateDateTime _deadLine;

    //on saute les accesseurs...

    }

    Jusqu'ici, tout va bien...Sauf que le marketing ne veut pas entendre parler de deadline pour ses items. On peut donc,

    soit renvoyer une information errone, pour continuer utiliser le IWorkItem courant, soit se conformer au principe

    ISP, et sparer notre interface en IWorkItem et IDeadLineDependent.

    publicinterfaceIWorkItem {

    voidManageWorkItem();

    stringToString();

    }

    publicinterfaceIDeadLineDependent {boolIsDeadLineExceeded();

    }

    L'intrt est que, si demain on a besoin d'une fonction ExtendDeadline dans IDeadLinedItem, cela n'impactera pas

    les WorkItems ne comportant pas de Deadline. Et si on ne le modifie pas, on n'introduit pas de bugs.

    VI - Inversion des dpendances (DIP: Dependency Inversion Principle)

    VI - A - Dfinition

    Le principe d'inversion des dpendances est un peu un principe secondaire. En effet, il rsulte d'une application

    stricte de deux autres principes, savoir les principes OCP et LSP. Sa dfinition est la suivante:

    Les modules de haut niveau ne doivent pas dpendre des modules de bas niveau. Les

    deux doivent dpendre d'abstractions.

    Les abstractions ne doivent pas dpendre des dtails. Les dtails doivent dpendre des

    abstractions.

    http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://localhost/var/www/apps/conversion/tmp/scratch_6/philippe.developpez.comhttp://www.developpez.com/
  • 5/25/2018 Solid Dot Net

    13/15

    Bonnes pratiques objet en .net : Introduction aux principes SOLID par Philippe Vialatte(philippe.developpez.com)

    - 13 -Copyright 2008 - Philippe Vialatte. Aucune reproduction, mme partielle, ne peut tre faite de ce site et del'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 Ede dommages et intrts. Droits de diffusion permanents accords developpez LLC.

    http://philippe.developpez.com/articles/SOLIDdotNet/

    Par module de haut niveau, on va entendre les modules contenant les fonctionnalits mtier, les modules de bas

    niveau grant la communication entre machines,les logs, la persistance. Si on change le mode de fonctionnement

    de la base (passage de Oracle SQL Server), du rseau (changement de protocole), de systme d'exploitation, les

    classes mtiers ne doivent pas tre impactes. Inversement, le fait de changer les rgles de validation au niveau de

    la partie mtier du framework ne doit pas demander une modification de la base de donnes ( la limite, modifier une

    fonction, mais ne pas changer les briques de base).

    Ce principe apporte:

    Une nette diminution du couplage

    Une meilleure encapsulation, l'implmentation concrte pouvant ventuellement tre choisie dynamiquement

    Ce principe est quivalent au principe d'Hollywood ("Ne nous appelez pas, nous vous

    appellerons"), qui est une forme plus gnrale d'inversion de contrle.

    Pour plus d'information sur ce principe, rendez-vous ici : (Wikipedia) : Inversion de

    contrle

    VI - B - Comment l'appliquer

    L'ide est que chaque point de contact entre deux modules soit matrialis par une abstraction.

    Par abstraction, on va entendre gnralement, une interface, mais on peut aussi considrer qu'une classe (une

    factory, par exemple) reprsente une abstraction d'une classe de niveau plus lev ou plus bas.

    VI - C - Exemple

    On va reprendre notre couche d'accs aux donnes, et la factory qui la manipule. Actuellement, les fonctions de

    chargement et de sauvegarde des objets mtier possdent une dpendance forte sur la couche d'accs aux donnes.

    On a donc un diagramme de classe quivalent a:

    Par consquent, on va avoir, dans l'tat, du mal isoler nos fonctions de cration d'objets de notre couche de donnes.

    Donc, on va avoir du mal les tester.

    Pour se conformer au principe DIP, on va modifier notre code de cette faon:

    http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://philippe.developpez.com/articles/SOLIDdotNet/http://fr.wikipedia.org/wiki/Inversion_de_contr%C3%B4lehttp://fr.wikipedia.org/wiki/Inversion_de_contr%C3%B4lehttp://philippe.developpez.com/articles/SOLIDdotNet/http://localhost/var/www/apps/conversion/tmp/scratch_6/philippe.developpez.comhttp://www.developpez.com/
  • 5/25/2018 Solid Dot Net

    14/15

    Bonnes pratiques objet en .net : Introduction aux principes SOLID par Philippe Vialatte(philippe.developpez.com)

    - 14 -Copyright 2008 - Philippe Vialatte. Aucune reproduction, mme partielle, ne peut tre faite de ce site et del'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 Ede dommages et intrts. Droits de diffusion permanents accords developpez LLC.

    http://philippe.developpez.com/articles/SOLIDdotNet/

    Pour aller encore plus prs du principe DIP, on pourrait ajouter encore une couche d'abstraction supplmentaire, en

    retournant des interfaces aux couches hautes.

    Une fois notre code factoris, va se poser la question de comment affecter la bonne implmentation de nos interfaces

    au bon composant.

    Une premire approche est de passer notre client une classe service choisie, ainsi qu'une rfrence sur un objet

    d'accs aux donnes. Cette approche va, en fait, dporter le choix de l'implmentation au niveau de la construction

    du client. Elle peut, mon avis, tre utilise pour des projets de petite taille. Pour des projets plus consquents,

    une seconde option est d'utiliser un configurateur externe, qui va, durant l'excution de notre code, renvoyer la

    bonne implmentation concrte de notre abstraction. Un certain nombre d'outils d'injection de dpendance sont

    disponibles et matures, je vous renvoie Google pour plus d'information sur ces outils. Vous trouverez, par exemple,

    StructureMap, Castle Windsor, ou, chezMicrosoft, Unity.

    L'idal est de chercher tendre vers ce principe, pas forcement de l'appliquer la lettre, ce qui peut se montrer

    contre-productif.

    En effet, pour se conformer 100% ce principe, il faudrait que:

    aucune variable ne rfrence une classe concrte

    aucune classe ne drive d'une classe concrte

    aucune classe ne rcrive une mthode d'une de ses classes de base.

    VII - Conclusion

    Ces principes peuvent s'noncer clairement, les utiliser demande de les conserver l'esprit durant chaque session

    de dveloppement, et le cot initial d'introduction peut tre dcourageant pour certains projets.

    Pour cette raison, ils sont souvent utiliss conjointement avec une mthodologie Agile, qu'elle soit XP, Scrum ou

    autre, supporte en tout cas par une panoplie de tests unitaires. En conclusion, le choix de se conformer ou non

    ces principes doit donc se faire en fonction du contexte du projet, et de l'importance que l'on donne la qualit et

    l'volutivit du programme dvelopp. Il est nanmoins toujours utile d'en avoir au moins entendu parler :).

    Pour un approfondissement avec des gens beaucoup plus intelligents que moi, je vous

    invite vous rendre sur les forums de la communaut Alt.Net, o j'ai, pour la premire

    fois, entendu parler des principes SOLID et de lire le livre de Robert Martin.

    http://philippe.developpez.com/articles/SOLIDdotNet/http://structuremap.sourceforge.net/http://structuremap.sourceforge.net/http://structuremap.sourceforge.net/http://www.castleproject.org/container/index.htmlhttp://www.castleproject.org/container/index.htmlhttp://www.amazon.com/exec/obidos/ASIN/0135974445/qid=1116531248/sr=2-1/ref=pd_bbs_b_2_1/002-3906371-8676026http://altdotnet.org/http://www.codeplex.com/unity/http://www.castleproject.org/container/index.htmlhttp://structuremap.sourceforge.net/http://philippe.developpez.com/articles/SOLIDdotNet/http://localhost/var/www/apps/conversion/tmp/scratch_6/philippe.developpez.comhttp://www.developpez.com/
  • 5/25/2018 Solid Dot Net

    15/15

    Bonnes pratiques objet en .net : Introduction aux principes SOLID par Philippe Vialatte(philippe.developpez.com)

    - 15 -Copyright 2008 - Philippe Vialatte. Aucune reproduction, mme partielle, ne peut tre faite de ce site et del'ensemble de son contenu : textes,documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 Ede dommages et intrts. Droits de diffusion permanents accords developpez LLC.

    http://philippe.developpez.com/articles/SOLIDdotNet/

    VIII - Remerciements

    Merci tomlevpour sa premire relecture (sans laquelle l'article serait srement moins intressant), et Skalppour

    ses corrections

    http://philippe.developpez.com/articles/SOLIDdotNet/http://www.developpez.net/forums/u125794/skalp/http://www.developpez.net/forums/u30665/tomlev/http://philippe.developpez.com/articles/SOLIDdotNet/http://localhost/var/www/apps/conversion/tmp/scratch_6/philippe.developpez.comhttp://www.developpez.com/