les design patterns en ruby

Upload: bnamustafa

Post on 08-Jul-2015

232 views

Category:

Documents


1 download

TRANSCRIPT

Rfrence

Les

design patterns en RubyRuss Olsen

Rseaux et tlcom Programmation

Gnie logiciel

Scurit Systme dexploitation

Version franaise par Laurent Julliard, Mikhail Kachakhidze et Richard Piacentini

Les design patterns en RubyRuss Olsen

Pearson Education France a apport le plus grand soin la ralisation de ce livre an de vous fournir une information complte et able. Cependant, Pearson Education France nassume de responsabilits, ni pour son utilisation, ni pour les contrefaons de brevets ou atteintes aux droits de tierces personnes qui pourraient rsulter de cette utilisation. Les exemples ou les programmes prsents dans cet ouvrage sont fournis pour illustrer les descriptions thoriques. Ils ne sont en aucun cas destins une utilisation commerciale ou professionnelle. Pearson Education France ne pourra en aucun cas tre tenu pour responsable des prjudices ou dommages de quelque nature que ce soit pouvant rsulter de lutilisation de ces exemples ou programmes. Tous les noms de produits ou marques cits dans ce livre sont des marques dposes par leurs propritaires respectifs.Publi par Pearson Education France 47 bis, rue des Vinaigriers 75010 PARIS Tl. : 01 72 74 90 00 Mise en pages : TyPAO ISBN : 978-2-7440-4018-4 Copyright 2009 Pearson Education France Tous droits rservs ISBN original : 978-0-321-49045-2 Copyright 2008 Pearson Education, Inc. All rights reserved Titre original : Design Patterns in Ruby Traduit de lamricain par Laurent Julliard, Mikhail Kachakhidze et Richard Piacentini

Aucune reprsentation ou reproduction, mme partielle, autre que celles prvues larticle L. 122-5 2 et 3 a) du code de la proprit intellectuelle ne peut tre faite sans lautorisation expresse de Pearson Education France ou, le cas chant, sans le respect des modalits prvues larticle L. 122-10 dudit code. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from Pearson Education, Inc.

Karen, qui a permis tout ceci, et Jackson, qui y donne un sens.

Table des matires

Prface ldition franaise ............................................................................................ Prface ...............................................................................................................................

XIII XV

Avant-propos ..................................................................................................................... XVII qui est destin ce livre ? .......................................................................................... XIX Comment ce livre est-il organis ? ............................................................................. XIX Avertissement ............................................................................................................. XIX Le style de code utilis dans ce livre .......................................................................... XX propos de lauteur ......................................................................................................... XXIII Partie I Patterns et Ruby Chapitre 1. Amliorer vos programmes avec les patterns ........................................... The Gang of Four (la bande des quatre) ..................................................................... Patterns des Patterns ................................................................................................... Sparer ce qui change de ce qui reste identique .............................................. Programmer par interface et non par implmentation ..................................... Prfrer la composition lhritage ................................................................ Dlguer, dlguer, dlguer ........................................................................... Vous naurez pas besoin de a ......................................................................... Quatorze sur vingt-trois .............................................................................................. Patterns en Ruby ? ...................................................................................................... Chapitre 2. Dmarrer avec Ruby ................................................................................... Ruby interactif ............................................................................................................ Afcher Hello World .................................................................................................. Variables ..................................................................................................................... Fixnums et Bignums ................................................................................................... Nombres virgule ottante ........................................................................................ 3 4 5 5 6 7 11 12 14 16 19 20 20 22 24 25

VI

Les design patterns en Ruby

Il ny a pas de types primitifs ici ................................................................................ Mais, parfois, il ny a pas dobjet ............................................................................... Vrit, mensonges et nil ............................................................................................. Dcisions, dcisions ................................................................................................... Boucles ....................................................................................................................... Plus de dtails sur les chanes de caractres .............................................................. Symboles .................................................................................................................... Tableaux ...................................................................................................................... Tableaux associatifs .................................................................................................... Expressions rgulires ................................................................................................ Votre propre classe ...................................................................................................... Accs aux variables dinstance ................................................................................... Un objet demande : qui suis-je ? ................................................................................ Hritage, classes lles et classes mres ...................................................................... Options pour les listes darguments ............................................................................ Modules ...................................................................................................................... Exceptions .................................................................................................................. Threads ....................................................................................................................... Grer des chiers de code source spars .................................................................. En conclusion ............................................................................................................. Partie II Patterns en Ruby Chapitre 3. Varier un algorithme avec le pattern Template Method .......................... Faire face aux ds de la vie ...................................................................................... Sparer les choses qui restent identiques .................................................................... Dcouvrir le pattern Template Method ....................................................................... Mthodes daccrochage .............................................................................................. Mais o sont passes toutes les dclarations ? ........................................................... Types, scurit et exibilit ........................................................................................ Les tests unitaires ne sont pas facultatifs .................................................................... User et abuser du pattern Template Method ............................................................... Les Templates dans le monde rel .............................................................................. En conclusion ............................................................................................................. Chapitre 4. Remplacer un algorithme avec le pattern Strategy .................................. Dlguer, dlguer et encore dlguer ........................................................................ Partager les donnes entre lobjet contexte et lobjet stratgie ..................................

26 27 27 29 30 32 34 35 36 37 38 40 42 42 43 45 47 48 49 50

53 54 55 58 59 61 61 64 65 67 67 69 69 72

Table des matires

VII

Typage la canard une fois de plus ............................................................................ Procs et blocs .............................................................................................................. Stratgies rapides et pas trs propres .......................................................................... User et abuser du pattern Strategy .............................................................................. Le pattern Strategy dans le monde rel ...................................................................... En conclusion ............................................................................................................. Chapitre 5. Rester inform avec le pattern Observer .................................................. Rester inform ............................................................................................................ Une meilleure faon de rester inform ....................................................................... Factoriser le code de gestion du sujet ......................................................................... Des blocs de code comme observateurs ..................................................................... Variantes du pattern Observer ..................................................................................... User et abuser du pattern Observer ............................................................................. Le pattern Observer dans le monde rel ..................................................................... En conclusion ............................................................................................................. Chapitre 6. Assembler le tout partir des composants avec Composite .................... Le tout et ses parties ................................................................................................... Crer des composites .................................................................................................. Rafner le pattern Composite avec des oprateurs ..................................................... Un tableau comme composite ? .................................................................................. Une diffrence embarrassante .................................................................................... Pointeurs dans les deux sens ....................................................................................... User et abuser du pattern Composite .......................................................................... Les composites dans le monde rel ............................................................................ En conclusion ............................................................................................................. Chapitre 7. Accder une collection avec lItrateur .................................................. Itrateurs externes ....................................................................................................... Itrateurs internes ....................................................................................................... Itrateurs internes versus itrateurs externes .............................................................. Lincomparable Enumerable ...................................................................................... User et abuser du pattern Itrateur .............................................................................. Les itrateurs dans le monde rel ............................................................................... En conclusion ............................................................................................................. Chapitre 8. Effectuer des actions avec Command ........................................................ Lexplosion de sous-classes ........................................................................................ Un moyen plus simple ................................................................................................ Des blocs de code comme commandes ......................................................................

73 75 78 80 80 82 83 83 85 88 91 92 92 94 95 97 97 100 103 104 105 106 107 108 109 111 111 113 114 116 117 119 122 123 124 125 126

VIII

Les design patterns en Ruby

Les commandes denregistrement .............................................................................. Annuler des actions avec Command .......................................................................... Crer des les de commandes .................................................................................... User et abuser du pattern Command ........................................................................... Le pattern Command dans le monde rel ................................................................... Migration ActiveRecord .................................................................................. Madeleine ........................................................................................................ En conclusion ............................................................................................................. Chapitre 9. Combler le foss avec lAdapter ................................................................. Adaptateurs logiciels .................................................................................................. Les interfaces presque parfaites .................................................................................. Une alternative adaptative ? ........................................................................................ Modier une instance unique ..................................................................................... Adapter ou modier ? ................................................................................................. User et abuser du pattern Adapter ............................................................................... Le pattern Adapter dans le monde rel ....................................................................... En conclusion ............................................................................................................. Chapitre 10 . Crer un intermdiaire pour votre objet avec Proxy ............................ Les proxies la rescousse ........................................................................................... Un proxy de contrle daccs ..................................................................................... Des proxies distants .................................................................................................... Des proxies virtuels vous rendre paresseux ............................................................. liminer les mthodes ennuyeuses des proxies .......................................................... Les mthodes et le transfert des messages ...................................................... La mthode method_missing .......................................................................... Envoi des messages ......................................................................................... Proxies sans peine ........................................................................................... User et abuser du pattern Proxy .................................................................................. Proxies dans le monde rel ......................................................................................... En conclusion ............................................................................................................. Chapitre 11. Amliorer vos objets avec Decorator ....................................................... Dcorateurs : un remde contre le code laid .............................................................. La dcoration formelle ............................................................................................... Diminuer leffort de dlgation .................................................................................. Les alternatives dynamiques au pattern Decorator ..................................................... Les mthodes dencapsulation ........................................................................ Dcorer laide de modules ............................................................................ User et abuser du pattern Decorator ...........................................................................

127 130 132 133 134 134 135 138 139 140 142 144 145 147 147 148 149 151 152 153 155 156 157 158 159 160 160 163 164 165 167 167 172 173 174 174 175 176

Table des matires

IX

Les dcorateurs dans le monde rel ............................................................................ En conclusion ............................................................................................................. Chapitre 12. Crer un objet unique avec Singleton ..................................................... Objet unique, accs global .......................................................................................... Variables et mthodes de classe .................................................................................. Variables de classe ........................................................................................... Mthodes de classe .......................................................................................... Premire tentative de cration dun singleton Ruby ................................................... Gestion de linstance unique ........................................................................... Sassurer de lunicit ....................................................................................... Le module Singleton ................................................................................................... Singletons instanciation tardive ou immdiate ........................................................ Alternatives au singleton classique ............................................................................. Variables globales en tant que singletons ........................................................ Des classes en tant que singletons ................................................................... Des modules en tant que singletons ................................................................ Ceinture de scurit ou carcan ? ................................................................................. User et abuser du pattern Singleton ............................................................................ Ce sont simplement des variables globales, nest-ce pas ? ............................. Vous en avez combien, des singletons ? .......................................................... Singletons pour les intimes ............................................................................. Un remde contre les maux lis aux tests ....................................................... Les singletons dans le monde rel .............................................................................. En conclusion ............................................................................................................. Chapitre 13. Choisir la bonne classe avec Factory ....................................................... Une autre sorte de typage la canard ......................................................................... Le retour du pattern Template Method ....................................................................... Des mthodes factory avec des paramtres ................................................................ Les classes sont aussi des objets ................................................................................ Mauvaise nouvelle : votre programme a du succs .................................................... Cration de lots dobjets ............................................................................................. Des classes sont des objets (encore) ........................................................................... Proter du nommage .................................................................................................. User et abuser des patterns Factory ............................................................................ Les factories dans le monde rel ................................................................................ En conclusion ............................................................................................................. Chapitre 14. Simplier la cration dobjets avec Builder ............................................ Construire des ordinateurs ..........................................................................................

177 178 179 179 180 180 181 182 183 184 184 185 185 185 186 188 188 190 190 190 191 193 193 194 195 196 198 200 202 203 204 207 208 209 209 211 213 214

X

Les design patterns en Ruby

Des objets builder polymorphes ................................................................................. Les builders peuvent garantir la validit des objets .................................................... Rutilisation de builders ............................................................................................. Amliorer des objets builder avec des mthodes magiques ....................................... User et abuser du pattern Builder ............................................................................... Des objets builder dans le monde rel ........................................................................ En conclusion ............................................................................................................. Chapitre 15. Assembler votre systme avec Interpreter .............................................. Langage adapt la tche ........................................................................................... Dvelopper un interprteur ......................................................................................... Un interprteur pour trouver des chiers .................................................................... Retrouver tous les chiers ............................................................................... Rechercher des chiers par nom ..................................................................... Des grands chiers et des chiers ouverts en criture .................................... Des recherches plus complexes laide des instructions Not, And et Or ....... Crer un AST .............................................................................................................. Un analyseur syntaxique simple ...................................................................... Et un interprteur sans analyseur ? .................................................................. Dlguer lanalyse XML ou YAML ? ........................................................ Racc pour des analyseurs plus complexes ....................................................... Dlguer lanalyse Ruby ? ........................................................................... User et abuser du pattern Interpreter .......................................................................... Des interprteurs dans le monde rel .......................................................................... En conclusion ............................................................................................................. Partie III Les patterns Ruby Chapitre 16. Ouvrir votre systme avec des langages spciques dun domaine ...... Langages spciques dun domaine ........................................................................... Un DSL pour des sauvegardes de chiers .................................................................. Cest un chier de donnes, non, cest un programme ! ............................................ Dvelopper PackRat ................................................................................................... Assembler notre DSL ................................................................................................. Rcolter les bnces de PackRat .............................................................................. Amliorer PackRat ..................................................................................................... User et abuser des DSL internes ................................................................................. Les DSL internes dans le monde rel ......................................................................... En conclusion .............................................................................................................

216 219 219 220 221 222 223 225 226 226 229 229 230 231 232 234 234 236 237 238 238 238 239 240

245 245 246 247 248 250 251 252 254 254 256

Table des matires

XI

Chapitre 17. Crer des objets personnaliss par mta-programmation .................... Des objets sur mesure, mthode par mthode ............................................................ Des objets sur mesure, module par module ................................................................ Ajouter de nouvelles mthodes .................................................................................. Lobjet vu de lintrieur .............................................................................................. User et abuser de la mta-programmation .................................................................. La mta-programmation dans le monde rel .............................................................. En conclusion ............................................................................................................. Chapitre 18. Convention plutt que conguration ....................................................... Une bonne interface utilisateur... pour les dveloppeurs ............................................ Anticiper les besoins ....................................................................................... Ne le dire quune seule fois ............................................................................. Fournir un modle ........................................................................................... Une passerelle de messages ........................................................................................ Slectionner un adaptateur ......................................................................................... Charger des classes ..................................................................................................... Ajouter un niveau de scurit ..................................................................................... Aider un utilisateur dans ses premiers pas ................................................................. Rcolter les bnces de la passerelle de messages ................................................... User et abuser du pattern Convention plutt que conguration ................................. Convention plutt que conguration dans le monde rel ........................................... En conclusion ............................................................................................................. Conclusion ......................................................................................................................... Annexes Annexe A. Installer Ruby ............................................................................................... Installer Ruby sous Microsoft Windows .................................................................... Installer Ruby sous Linux ou un autre systme de type UNIX .................................. Mac OS X ................................................................................................................... Annexe B. Aller plus loin ................................................................................................ Design patterns ........................................................................................................... Ruby ........................................................................................................................... Expressions rgulires ................................................................................................ Blogs et sites Web ....................................................................................................... propos des traducteurs ................................................................................................. Index ..................................................................................................................................

257 258 259 261 264 265 266 269 271 273 273 274 274 275 277 278 281 283 284 284 285 286 287

291 291 291 292 293 293 294 295 296 297 299

Prface ldition franaise

Design Patterns In Ruby started out as a 900 word blog article that I wrote in one afternoon. I certainly never dreamed that those 17 or so paragraphs would lead to a book in English, let alone to a French edition. Perhaps this is not so surprising, because that is what Ruby is like: Ruby changes the odds, it makes the difcult easy and many impossible things possible. But the language is only half the story: Every programming language needs an enthusiastic user community to be successful. Here too Ruby has been specially blessed. Certainly I am grateful to Richard Piacentini, Laurent Julliard and Mikhail Kachakhidze for making this French edition possible.Russ Olsen Virginia, April 2008

Cest avec un plaisir non dissimul que nous livrons aux lecteurs francophones cette traduction de louvrage de Russ Olsen sur les patrons de conception (design patterns) en Ruby. Et ce pour plusieurs raisons. Tout dabord parce que nous disposons dsormais dun ouvrage supplmentaire en franais qui met en avant le langage Ruby. En effet, si les publications sur le framework web Ruby on Rails sont aujourdhui lgion (plus de 20 titres en franais ce jour !), il nen va pas de mme pour le langage Ruby qui ne compte que quelques titres. Ensuite parce que ladaptation Ruby dun des ouvrages les plus clbres de lhistoire de linformatique, Design Patterns de Erich Gamma, Richard Helm, Ralph Johnson et John M. Vlissides (souvent appel "le GoF", abrviation de The Gang of Four ou "la bande des quatre", en rfrence aux quatre auteurs de louvrage) est une indniable marque de maturit du langage Ruby lui-mme, mais aussi de sa communaut. Les centaines de milliers de dveloppeurs qui ont dcouvert Rails au cours des deux dernires annes ont aussi pris conscience que derrire Rails se cache Ruby, un langage de programmation totalement orient objet, incroyablement agile et expressif quon peut utiliser dans de trs nombreux domaines (algorithmie, systme, rseau, modlisation, etc.).

XIV

Les design patterns en Ruby

Les patrons de conception sont dailleurs un thme rv pour mettre en lumire les qualits de ce langage cr en 1995 par un universitaire japonais, Yukihiro Matsumoto ("Matz" pour les intimes...). Vous pourrez notamment constater quel point lexpressivit et les capacits dynamiques du langage Ruby permettent de saffranchir des lourdeurs et du code fastidieux souvent ncessaire la mise en uvre de ces mmes patrons de conception dans dautre langages comme C++ ou Java. Ces qualits ont aussi inspir la communaut Ruby la cration de nouveaux patrons de conception comme les DSL (langages spciques dun domaine) ou "Convention plutt que Conguration", que vous dcouvrirez la n de louvrage. Avant de vous laisser la lecture de ce livre qui est dj une rfrence outre-Atlantique, nous aimerions vous mettre en garde et vous proposer un sujet de rexion. Lavertissement porte sur le caractre terriblement "addictif" du langage Ruby : ceux dentre vous qui sapprtent ctoyer Ruby pour la premire fois risquent fort den ressentir les effets secondaires, cest--dire une certaine aversion pour les langages typage statique utiliss aujourdhui dans lindustrie, comme C++, C# ou Java. Pour vous aider surmonter cette impression de clivage profond, nous terminerons en vous livrant quelques lments de rexion. Sun et Microsoft ont tout deux lanc le portage du langage Ruby sur leur machine virtuelle (respectivement Jruby et RubyDLR) et Apple livre dsormais Ruby et Rails en standard avec ces kits de dveloppement. Tous ont compris que dans certains domaines les atouts du langage Ruby permettent des gains de productivit considrables sans pour autant hypothquer ni lexistant ni la qualit des logiciels produits. Les langages dynamiques orients objet, apparus dans les annes 1970 avec Smalltalk, sont lorigine de la plupart des concepts de programmation utiliss aujourdhui. Longtemps clipss par les langages "poids lourd" (dans tous les sens du terme !) de lindustrie, les voici qui reviennent en force sur le devant de la scne et Ruby en est assurment lun des plus dignes reprsentants. Bonne lecture !

Laurent Julliard Richard Piacentini

Prface

Design patterns. Catalogue de modles de conceptions rutilisables, connu sous le nom affectueux de "livre du Gang of Four" (ou GoF), est le premier ouvrage de rfrence publi sur ce sujet, devenu depuis trs populaire. Avec plus dun demi-million dexemplaires vendus, cet ouvrage a sans doute inuenc la faon de penser et de coder de millions de programmeurs dans le monde entier. Je me rappelle distinctement le jour o jai achet mon premier exemplaire de ce livre la n des annes 1990. En partie cause des recommandations enthousiastes de mes amis, je lai considr comme une tape incontournable vers ma maturit en tant que programmeur. Jai aval le livre en quelques jours en essayant dinventer des applications pratiques pour chacun des patterns. Il est gnralement reconnu que la caractristique la plus utile des patterns rside dans le vocabulaire quils proposent. Ce vocabulaire permet aux programmeurs dexprimer des modles de conception dans les conversations quils peuvent avoir entre eux en cours de dveloppement. Cest particulirement vrai pour la programmation en paire (pair programming), la pierre angulaire de la programmation agile de type Extreme Programming, ainsi que pour dautres techniques agiles, o la conception est une activit quotidienne et collective. Il est fantastiquement pratique de pouvoir dire votre collgue "Je pense quici nous avons besoin dune stratgie" ou "Ajoutons cette fonctionnalit sous la forme dun observateur". Dans certaines entreprises, la connaissance de design patterns est mme devenue un moyen simple pour ltrer des candidats : "Quel est votre pattern prfr ?" "Hum... Factory ?" "Merci dtre venu, au revoir." Il est vrai que la notion de pattern prfr est assez trange. Votre pattern prfr doit tre par dnition celui qui est le plus adapt aux circonstances. Une des erreurs classiques faites par des programmeurs inexpriments qui commencent apprendre les patterns est dimplmenter un pattern comme une n en soi et non pas comme un outil. Pourquoi implmenter des patterns dans le but de samuser ?

XVI

Les design patterns en Ruby

Dans le monde des langages typage statique, limplmentation de design patterns prsente un certain nombre de ds techniques. Dans le meilleur des cas, vous allez utiliser des techniques de ninja pour dmontrer toute votre habilet au codage. Dans le pire des scnarii, vous vous retrouverez avec un tas de code gnrique totalement rpugnant. Pour des allums de la programmation comme moi, cela suft rendre le sujet sur les design patterns particulirement amusant. Est-ce que les design patterns du GoF sont difciles implmenter en Ruby ? Pas vraiment. Tout dabord, labsence de typage statique rduit le cot de vos programmes en terme de lignes de code. La bibliothque standard de Ruby permet dinclure les patterns les plus frquents en une ligne, alors que les autres sont essentiellement incorpors dans le langage mme. Par exemple, selon le GoF un objet Command encapsule du code qui sait effectuer une tche ou excuter un fragment de code un moment donn. Cette description correspond galement un bloc de code un Proc en Ruby. Russ a travaill avec Ruby depuis 2002 et il sait que la majorit des dveloppeurs Ruby expriments ont dj une bonne matrise des design patterns et de leurs applications. Daprs moi, son d principal consistait crire un livre qui soit la fois pertinent pour des programmeurs Ruby professionnels mais qui puisse aussi proter aux dbutants. Je pense quil a russi et je suis convaincu que vous serez daccord avec moi sur ce point. Prenons notre exemple dun objet Command : dans sa forme simple, il peut tre facilement implment avec un bloc Ruby, mais il suft dy ajouter de linformation sur son tat et un peu de code mtier et limplmentation devient tout de suite plus complexe. Russ nous fournit des conseils avertis spciques Ruby et prts tre appliqus. Ce livre prsente aussi lavantage dinclure de nouveaux design patterns spciques Ruby. Russ a identi et expliqu en dtail plusieurs modles de conception dont un de mes prfrs : Internal Domain Specic Languages (les langages internes spciques dun domaine). Je crois que sa vision de ce pattern comme lvolution du pattern Interpreter est une analyse de rfrence signicative et sans prcdent. Enn, je pense que ce livre sera extrmement bnque ceux qui dbutent leur carrire dans le monde Ruby ou qui migrent dautres langages, comme PHP, qui ne mettent pas autant laccent sur les pratiques de conception oriente objet. En dcrivant les design patterns, Russ a illustr des solutions essentielles aux problmes que lon rencontre quotidiennement dans le dveloppement de programmes denvergure en Ruby : ce sont des conseils dune valeur inestimable pour un dbutant. Je suis sr que ce livre sera le cadeau que joffrirai en priorit mes amis et collgues dbutants. Obie Fernandez, diteur de la srie Professional Ruby

Avant-propos

Un ancien collgue disait que les gros livres sur les design patterns tmoignent de linadquation dun langage de programmation. Il entendait par l que les patterns sont des idiomes courants dans le code et quun bon langage de programmation doit rendre leur implmentation extrmement simple. Un langage idal intgrerait les design patterns jusquau point de les rendre quasiment transparents. Pour vous donner un exemple extrme, la n des annes 1980 jai travaill sur un projet o lon produisait du code C orient objet. Oui, C et non pas C++. Voici comment nous avons russi cet exploit. Chaque objet (en ralit une structure en C) pointait vers un tableau de pointeurs de fonction. Pour utiliser lobjet nous retrouvions le tableau correspondant et nous appelions ses fonctions, en simulant ainsi des appels de mthodes. Ctait trange et pas trs propre, mais cela fonctionnait. Si nous y avions pens, nous aurions pu appeler cette technique "le pattern orientobjet". videmment, avec larrive de C++, puis de Java, notre modle sest incorpor si profondment au langage quil est devenu invisible. Aujourdhui, lorientation objet nest plus considre comme un pattern cest trop simple. Pourtant, beaucoup de choses demeurent encore complexes. Design patterns. Catalogue de modles de conceptions rutilisables, crit par Gamma, Helm, Johnson et Vlissides, qui a acquis une notorit bien mrite, fait partie dun programme de lecture obligatoire pour chaque ingnieur logiciel. Or limplmentation des modles dcrits dans cet ouvrage avec les langages rpandus (Java, C++ et peut-tre C#) ressemble beaucoup au systme " lancienne" que jai conu dans les annes 1980. Trop pnible. Trop verbeux. Trop enclin aux bugs. Le langage de programmation Ruby se rapproche davantage de lidal de mon vieil ami il facilite si bien limplmentation des patterns que la plupart du temps ceux-ci se fondent dans larrire-plan.

XVIII Les design patterns en Ruby

Cette facilit est due plusieurs facteurs :m

Ruby est un langage dynamiquement typ. En supprimant le typage statique, Ruby rduit de faon signicative le surcot de code ncessaire la construction de la plupart des programmes, y compris ceux qui implmentent des patterns. Ruby a des fermetures lexicales. Il permet de passer des fragments de code avec leur environnement sans recourir la construction de classes et dobjets inutiles. Les classes Ruby sont de vrais objets. Le fait quune classe soit un objet comme un autre nous permet de manipuler une classe Ruby au moment de lexcution. On peut crer de nouvelles classes ou modier des classes existantes en ajoutant ou en supprimant ses mthodes. On peut mme cloner une classe et modier la copie sans toucher loriginal. Ruby prsente un modle lgant de la rutilisation de code. En plus de lhritage classique, Ruby permet de dnir des mixins qui fournissent un moyen simple mais exible dcrire du code partageable entre plusieurs classes.

m

m

m

Tout cela rend le code Ruby trs compact. En Ruby, tout comme en Java et C++, on peut implmenter des ides trs sophistiques, mais Ruby propose des moyens beaucoup plus efcaces de cacher les dtails de leur implmentation. Comme vous le verrez par la suite, de nombreux "design patterns" qui ncessitent dinterminables lignes de code gnrique dans les langages statiques traditionnels ne requirent quune ou deux lignes en Ruby. Vous pouvez transformer une classe en un singleton avec la simple commande include Singleton. Vous pouvez dlguer aussi facilement quhriter. Ruby vous donne les outils pour exprimer davantage de choses intressantes chaque ligne, ce qui rduit votre base de code. Il sagit non seulement dviter de taper sur le clavier mais aussi dappliquer le principe DRY (Dont Repeat Yourself). Je doute que quelquun dans le monde daujourdhui regrette mon vieux pattern orient-objet en C. Il fonctionnait, mais ma demand beaucoup defforts. De mme, les implmentations traditionnelles des nombreux "design patterns" fonctionnent, mais vous demandent beaucoup defforts. Ruby reprsente un vrai pas en avant car il suft de faire le travail une fois et de le dissocier de votre code principal. En rsum, Ruby permet de se concentrer sur des solutions des problmes concrets, au lieu de la tuyauterie. Je souhaite que ce livre vous montre comment y parvenir.

Avant-propos

XIX

qui est destin ce livre ?Ce livre sadresse aux programmeurs qui souhaitent apprendre dvelopper des applications en Ruby. Les concepts de base de la programmation oriente objet doivent tre connus, mais vous naurez besoin daucune connaissance particulire en matire de design patterns. Vous pourrez les apprendre en lisant ce livre. Vous naurez pas besoin non plus dune matrise approfondie de Ruby pour tirer pleinement parti de ce livre. Une introduction rapide au langage vous est propose au Chapitre 2, les autres points spciques Ruby tant expliqus au l de louvrage.

Comment ce livre est-il organis ?Le prsent ouvrage est divis en trois parties. La Partie 1 est constitue de deux chapitres dintroduction : le premier passe en revue lhistorique et les raisons qui ont prsid la naissance des design patterns et le second vous propose un tour dhorizon du langage Ruby sufsamment toff pour que vous "deveniez dangereux". La Partie 2, qui reprsente la majeure partie de ce livre, examine du point de vue Ruby un certain nombre de patterns du Gang of Four. Quels sont les problmes que rsout un pattern ? quoi ressemblent limplmentation traditionnelle celle fournie par le Gang of Four et celle en Ruby ? Le pattern est-il justi en Ruby ? Existe-t-il des alternatives en Ruby pour faciliter la solution ce problme ? Autant de questions auxquelles nous apportons des rponses dans cette seconde partie. La Partie 3 couvre trois patterns qui sont apparus avec lusage avanc de Ruby.

AvertissementJe ne peux pas signer de mon nom un livre sur les design patterns sans rpter le mantra que je murmure depuis des annes : les design patterns sont des solutions "prcuites" aux problmes courants de programmation. Idalement, lorsque vous rencontrez le bon problme il suft dappliquer le bon design pattern et vous avez la solution. Cest cette premire partie de la phrase attendre de rencontrer le "bon problme" qui semble poser problme certains ingnieurs. On ne peut pas considrer quun pattern est appliqu correctement si le problme que ce pattern est cens rsoudre nexiste pas. Lusage imprudent de tous les patterns pour rgler des problmes qui nen sont pas est lorigine de la mauvaise rputation que se sont taills les design patterns dans certains milieux. Je me permets dafrmer quen Ruby il est plus facile dcrire un adaptateur qui utilise une factory pour obtenir un proxy dun builder, qui cre son tour une commande pour coordonner lopration en vue dadditionner deux plus deux.

XX

Les design patterns en Ruby

Cest vrai, Ruby rend le processus effectivement plus facile, mais mme en Ruby cela na aucun sens. On ne peut non plus voir la construction de programmes comme un processus de recombinaison de patterns existants. Tout programme intressant a des sections uniques : du code qui est parfait pour un problme donn et aucun autre. Les design patterns sont l pour vous aider reconnatre et rsoudre des problmes de conception frquents et rptitifs. Lavantage des design patterns, cest que vous pouvez rapidement vacuer des problmes que quelquun a dj rsolus pour passer aux choses vritablement difciles, savoir le code spcique votre situation. Les patterns ne sont pas une potion magique pour rgler tous vos soucis de conception. Ils ne sont quune technique une technique trs utile que vous pouvez utiliser en dveloppant des programmes.

Le style de code utilis dans ce livreSi la programmation en Ruby est si agrable, cest que le langage tente de seffacer. Sil existe plusieurs moyens senss dexprimer quelque chose, Ruby, en gnral, les propose tous :# Une faon de lexprimer if (divisor == 0) puts Division by zero end # Encore une puts Division by zero if (divisor == 0) # Et une troisime (divisor == 0) && puts(Division by zero)

Ruby nessaie pas dinsister sur lutilisation mticuleuse de la syntaxe. Lorsque le sens de linstruction est clair, Ruby permet domettre des lments syntaxiques. Par exemple, dhabitude vous pouvez omettre des parenthses dans les listes darguments quand vous appelez une mthode :puts(A fine way to call puts) puts Another fine way to call puts

Vous pouvez mme omettre des parenthses lorsque vous dnissez la liste darguments dune mthode ou dune expression conditionnelle :def method_with_3_args a, b, c puts "Method 1 called with #{a} #{b} #{c}" if a == 0 puts a is zero end end

Avant-propos

XXI

Le problme de ces raccourcis vient du fait que leur usage excessif a tendance embrouiller les dbutants. Une majorit des programmeurs qui dbutent en Ruby seraient plus rassurs parif file.eof? puts( Reached end of file ) end

ou mmeputs Reached end of file if file.eof?

que parfile.eof? && puts(Reached end of file)

Puisque ce livre se concentre plus sur la puissance et llgance inhrentes Ruby que sur la syntaxe, jai essay de faire en sorte que mes exemples ressemblent du code Ruby rel tout en restant comprhensibles par des dbutants. En pratique, cela signie que je prote des raccourcis les plus vidents mais que jvite volontairement des astuces plus radicales. Cela ne veut pas dire que je ne sois pas au courant ou que je ne soutienne pas lutilisation de la "stnographie" Ruby. Je suis simplement plus concentr sur la ncessit de faire passer le message de llgance conceptuelle de ce langage auprs des lecteurs dbutants. Vous aurez beaucoup doccasions dapprendre des raccourcis lorsque vous serez tomb fou amoureux de ce langage.

propos de lauteur

Russ Olsen est ingnieur logiciel avec son actif plus de vingt-cinq ans dexprience. Russ a dvelopp des logiciels dans des domaines aussi varis que la conception ou la production assiste par ordinateur, les systmes dinformation gographique, la gestion de documents et lintgration des systmes dinformation en entreprise. Il travaille actuellement sur des solutions de scurit et de dcouverte automatique de services SOA pour de grandes entreprises. Russ a contribu Ruby depuis 2002. Il est lauteur de ClanRuby, une tentative lpoque dajouter des fonctionnalits multimdias Ruby. Aujourdhui, il participe de nombreux projets open source y compris UDDI4R. Des articles techniques de Russ sont parus dans Javalobby, On Java chez OReilly ainsi que sur le site de Java Developers Journal. Russ est diplm de Temple University et habite en banlieue de Washington avec sa famille, deux tortues et un nombre indtermin de guppy. Russ est joignable par courrier lectronique [email protected].

Partie IPatterns et Ruby

1Amliorer vos programmes avec les patternsCest drle, mais les "design patterns" me rappellent toujours une certaine picerie. Encore lycen, javais dcroch un premier boulot temps partiel. Pendant quelques heures les jours de la semaine et le samedi toute la journe, je donnais un coup de main dans un petit commerce local. Toutes les tches peu qualies telles que lapprovisionnement des tagres ou encore le balayage du plancher faisaient partie de mes responsabilits. Au dbut, la vie de cette petite picerie me paraissait un trange mlange dimages (je nai jamais apprci laspect dun foie cru), de sons (mon patron avait t instructeur dans le corps des marines amricains et il savait impressionner par sa voix) et dodeurs (je vous passe les dtails). Pourtant, plus je travaillais chez Conrad Market, plus ces vnements isols se regroupaient pour former des procdures comprhensibles. Le matin, il fallait ouvrir la porte dentre, teindre lalarme et afcher le panneau "Oui ! Nous sommes ouverts". Le soir, le processus tait invers. Entre les deux je moccupais dun million de choses : approvisionner les tagres, aider les clients trouver le ketchup tout et nimporte quoi. Au fur et mesure que je faisais connaissance avec mes homologues dans les autres commerces, je dcouvrais que leur mode de fonctionnement tait quasiment le mme. Cela illustre la faon dont les gens ragissent face aux problmes et la complexit de la vie. Nous improvisons et trouvons des solutions rapides de nouveaux problmes, mais pour rpondre aux problmes rcurrents nous dveloppons des procdures standardises. Il ne faut pas rinventer la roue, comme dit le proverbe.

4

Patterns et Ruby

The Gang of Four (la bande des quatre)Rinventer la roue est un rel problme pour des ingnieurs logiciel. Personne naime faire et refaire la mme chose, mais lorsquon conoit des systmes il est parfois difcile de se rendre compte que le dispositif rotatoire de rduction de friction axe central que lon vient de raliser est effectivement une roue. La conception de logiciels peut devenir tellement complexe quil est facile de ne pas reconnatre les problmes types qui se prsentent nous de faon rpte et leurs solutions rcurrentes. En 1995, Erich Gamma, Richard Helm, Ralph Johnson et John Vlissides ont dcid de consacrer leur nergie un travail plus utile que la construction rpte de "roues". Sur la base du travail effectu entre autres par Christopher Alexander et Kent Beck, ils ont publi louvrage Design patterns. Catalogue de modles de conceptions rutilisables. Louvrage a t un succs instantan, rendant ses auteurs clbres (au moins dans le monde du dveloppement logiciel) sous le nom de "The Gang of Four" (le GoF ou la bande des quatre). Les membres du GoF ont accompli deux tches. Premirement, ils ont fait dcouvrir un grand nombre dingnieurs logiciel la notion des "design patterns" (modles de conception), un pattern tant une solution "prt--porter" un problme frquent de conception. Ils ont crit : "Nous devons regarder autour de nous et identier les solutions courantes aux problmes courants. Nous devons nommer chaque solution et dcrire les situations pour lesquelles son utilisation est approprie, ainsi que les cas o il faut opter pour une approche diffrente. Cette information sera consigne par crit an que la palette des modles de conception stoffe avec le temps." Deuximement, les membres du GoF ont identi, nomm et dcrit vingt-trois patterns initiaux, quils ont considrs comme des modles cls pour dvelopper des programmes orients objet propres et bien conus. Depuis la publication de Design Patterns, de nombreux livres ont suivi sur le sujet, dcrivant des patterns dans des domaines allant des microcontrleurs temps rel aux architectures dentreprise. Pourtant, les vingt-trois patterns recenss par le GoF sont rests au cur de la conception des logiciels orients objet en se concentrant sur des questions essentielles : comment les objets dans la plupart des systmes se rfrent lun lautre ? Comment doivent-ils tre coupls ? Quelles informations sur les autres objets doivent-ils avoir ? Comment remplacer des parties qui sont susceptibles de changer frquemment ?

Chapitre 1

Amliorer vos programmes avec les patterns

5

Patterns des PatternsEn rponse ces questions, les auteurs de Design Patterns ont formul plusieurs principes gnraux : des mta-design patterns. Pour moi, ces ides se rduisent quatre points :m m m m

sparer ce qui change de ce qui reste identique ; programmer par interface et non par implmentation ; prfrer la composition lhritage ; dlguer, dlguer, dlguer.

Jy ajouterai un point qui ne gure pas dans Design Patterns, mais qui dnit souvent mon approche de la conception de programmes :m

Vous naurez pas besoin de a.

Dans les sections suivantes, nous allons tudier comment chacun de ces principes conditionne la conception de logiciels. Sparer ce qui change de ce qui reste identique Le dveloppement de logiciels serait beaucoup plus simple si les choses ne changeaient pas. On pourrait crire des classes en tant sr quune fois termines elles continueront servir la mme tche. Mais le monde bouge, et dans le monde du dveloppement logiciel cest encore plus vrai. Les volutions du matriel informatique, des systmes dexploitation, des compilateurs ainsi que les corrections de bugs et les exigences qui varient perptuellement ont toutes un rle jouer. Lobjectif cl des ingnieurs logiciel est de dvelopper des systmes permettant de limiter les dgts. Dans un systme idal, tout changement serait local : on ne devrait jamais avoir besoin de revrier la totalit du code si le point A a t modi, ce qui vous a amen modier le point B, qui a dclench un changement de C, qui a eu une rpercussion sur Z. Comment atteindre ou au moins sapprocher du systme idal, dans lequel tout changement serait local ? Pour atteindre ce but il faut sparer les parties variables de celles qui restent identiques. Si vous pouvez identier quels aspects de votre systme sont susceptibles de changer, vous pourrez les isoler des parties plus stables. Il faudra toujours modier le code lorsque les besoins volueront ou lorsquon corrigera une anomalie, mais il y a peut-tre une chance pour que lon puisse contenir les modications dans ces portions de code que nous aurons isoles et protges an que le reste demeure inchang.

6

Patterns et Ruby

Mais comment maintenir cette quarantaine et prvenir la contamination des parties stables par des aspects variables ? Programmer par interface et non par implmentation crire du code faiblement coupl est toujours un bon dbut. Si nos classes sont conues pour une tche non triviale, elles doivent tre au courant lune de lautre. Mais que doivent-elles savoir lune de lautre exactement ? Le fragment de code Ruby suivant 1 cre une instance de classe Car et appelle la mthode dinstance drive :my_car = Car.new my_car.drive(200)

Il est clair que ce code est fortement li la classe Car. Il continuera fonctionner si lon a besoin de manipuler un seul vhicule. Si les exigences changent et quun autre mode de transport doit tre gr (par exemple lavion), nous nous retrouvons face un problme. Pour matriser deux types de transport on pourrait par exemple se contenter dcrire lhorreur suivante :# Grer des voitures et des avions if is_car my_car = Car.new my_car.drive(200) else my_plane = AirPlane.new my_plane.fly(200) end

Ce code nest pas seulement sale, mais il est aussi fortement coupl la fois aux voitures et aux avions. Cette structure pourrait tenir la route jusqu larrive dun bateau, ou dun train, ou dun vlo. Une meilleure solution serait de se rappeler les bases de la programmation oriente objet et dajouter une dose gnreuse de polymorphisme. Si les voitures, les avions et les bateaux implmentent une interface commune, le code peut tre amlior de faon suivante :my_vehicle = get_vehicle my_vehicle.travel(200)

En plus dtre du bon code orient objet bien lisible, cet exemple dmontre le principe de programmation par interface.1. Ne vous inquitez pas, si vous dmarrez avec Ruby. Le code utilis dans ce chapitre est trs basique. Le chapitre suivant prsente le langage plus en dtail. Il ne faut pas sinquiter si tout nest pas compltement clair pour le moment.

Chapitre 1

Amliorer vos programmes avec les patterns

7

Le code initial fonctionnait avec un seul type de vhicule une voiture , mais la nouvelle version gre tout objet de type Vehicle. Les dveloppeurs Java et C# suivent parfois ce conseil la lettre, puisque la dnition dinterfaces est un lment de ces langages. Ils extraient soigneusement toute la fonctionnalit principale dans plusieurs interfaces spares, qui peuvent ensuite tre implmentes par des classes concrtes. Gnralement, cest une bonne pratique, mais ce nest pas vraiment la philosophie sous-jacente au principe de programmation par interface. Lide consiste choisir le type le plus gnrique possible, ne pas appeler la voiture une voiture sil est possible de lappeler un vhicule, peu importe si Car et Vehicle sont des classes concrtes ou des interfaces abstraites. Cest mme mieux si lon peut choisir un supertype encore plus gnrique, par exemple un objet mobile. Comme vous le verrez par la suite, le langage Ruby, qui ninclut pas dinterfaces dans sa syntaxe1, vous encourage cependant programmer des interfaces utilisant des supertypes les plus gnriques possible. En crivant du code avec des types gnriques, par exemple en considrant tous les avions, les trains et les voitures comme des vhicules, nous rduisons le couplage de notre code. Au lieu davoir quarante-deux classes fortement lies des voitures, des bateaux et des avions, on nira peut-tre avec quarante classes qui ne manipuleront que la notion de vhicule. Il est probable que lon soit embt sil faut ajouter un nouveau type de vhicule correspondant aux deux classes qui restent, mais au moins on aura limit les dgts. Le fait dajouter seulement deux classes indique que nous avons russi le pari de sparer les parties variables (les deux classes) des parties stables (les quarante autres). Grce au faible couplage, nous diminuons considrablement le risque que la moindre modication dclenche une raction en chane dvastant la totalit du code. Nanmoins, programmer des interfaces nest pas la seule mesure prendre pour rendre le code rsistant aux changements. Il existe aussi la composition. Prfrer la composition lhritage Si votre introduction la programmation oriente objet a ressembl la mienne, vous avez d passer 10 minutes sur la dissimulation de linformation, 22 minutes sur les questions de visibilit et de porte et le reste du semestre sur lhritage. Une fois acquises les notions basiques des objets, champs et mthodes, le principal sujet intressant qui reste est lhritage, la partie la plus oriente objet de la programmation objet.1. Le langage Ruby inclut des modules qui ressemblent des interfaces Java. Vous trouverez plus de dtails sur des modules Ruby au Chapitre 2.

8

Patterns et Ruby

Lhritage rend possible limplmentation sans peine, il suft de sous-classer la classe Widget pour obtenir comme par magie laccs toutes ses fonctionnalits. Lhritage semble tre la panace. Besoin dimplmenter une voiture ? Il suft de sousclasser Vehicle, qui lui-mme est de type MovableObject, etc. De mme, dautres branches telles que AirPlane et MotorBoat peuvent apparatre ct (voir Figure 1.1). chaque niveau nous protons des fonctionnalits de la classe mre.Figure 1.1Proter au maximum de lhritageMovableObject

Vehicle

MotorBoat

Car

AirPlane

Toutefois, lhritage apporte son lot de dfauts. Lorsque vous dnissez une sous-classe dune classe existante, au lieu de crer deux entits spares vous obtenez deux classes qui sont intimement lies par limplmentation commune. Par nature, lhritage a tendance lier la classe lle et la classe mre. Il y a de fortes chances quune modication de comportement de la classe mre affecte le fonctionnement de la classe lle. De plus, la classe lle a un accs privilgi aux dtails dimplmentation de sa classe mre. Tout fonctionnement interne qui nest pas soigneusement cach est visible des sous-classes. Si lobjectif est de dvelopper des systmes faiblement coupls o le moindre changement ne provoque pas une raction en chane qui fait voler en clats tout le code, il ne faut pas se er compltement lhritage. Si lhritage pose autant de soucis, quelle est lalternative ? Eh bien, nous pouvons construire les comportements souhaits en ayant recours la composition. Au lieu de crer des classes qui hritent tous leurs talents de la classe mre, nous pouvons les laborer partir de composants mtier de base. Pour y arriver nous quipons nos objets avec des rfrences vers des objets-fournisseurs de fonctionnalits. Toute classe qui requiert ces fonctionnalits peut les appeler car elles sont encapsules dans lobjet-fournisseur. En bref, nous prfrons dnir un objet qui A une caractristique plutt quun objet qui EST de type donn.

Chapitre 1

Amliorer vos programmes avec les patterns

9

Pour reprendre lexemple prcdent, supposons que nous ayons une mthode qui simule une balade en voiture. La partie cl de cette balade est le dmarrage et larrt du moteur :class Vehicle # Diffrentes fonctionnalits des vhicules... def start_engine # Dmarrer le moteur end def stop_engine # Arrter le moteur end end class Car < Vehicle def sunday_drive start_engine # Aller se balader et ensuite revenir. stop_engine end end

La logique de ce code est la suivante : notre voiture a besoin de dmarrer et darrter le moteur. Cette fonctionnalit sappliquera dautres vhicules, pourquoi ne pas factoriser le code li au moteur et le placer dans la classe commune Vehicle (voir Figure 1.2).Figure 1.2Factoriser le code li au moteur dans la classe mreVehicle start_engine() stop_engine()

Car

Cest bien, mais tous les vhicules ne sont pas forcment quips dun moteur. Une intervention chirurgicale sera ncessaire sur des classes qui reprsentent des vhicules non motoriss (un vlo ou un bateau voile). Par ailleurs, moins de faire attention lors du dveloppement de la classe Vehicle, les dtails lis au moteur seront disponibles pour la classe Car. Aprs tout, le moteur est gr par la classe Vehicle, et lobjet Car nest quune sorte de Vehicle. Ce nest pas conforme au principe de sparation des parties variables et statiques. Toutes ces difcults peuvent tre vites si le code du moteur est plac dans sa propre classe totalement indpendante et dissocie de la classe parent de Car.

10

Patterns et Ruby

class Engine # Code li au moteur def start # Dmarrer le moteur end def stop # Arrter le moteur end end

Si chaque objet Car contient une rfrence vers son propre Engine, nous pourrions aller nous promener en voiture grce la composition.class Car def initialize @engine = Engine.new end def sunday_drive @engine.start # Aller se balader et ensuite revenir. @engine.stop end end

Lassemblage des fonctionnalits par composition (voir Figure 1.3) donne de nombreux avantages : les fonctions du moteur sont factorises dans une classe spare et sont prtes tre rutilises (encore une fois par le truchement de la composition !).Figure 1.3Assembler une voiture avec la compositionVehicle

Car

Engine start() stop()

Qui plus est, nous avons galement simpli la classe Vehicle en supprimant les fonctions du moteur. Nous avons aussi amlior le niveau dencapsulation : lextraction des fonctions du moteur offre dsormais une sparation nette par interface entre chaque voiture et son moteur. Dans la version initiale, fonde sur lhritage, tous les dtails de limplmentation du moteur taient exposs toutes les mthodes de la classe Vehicle. Dans la

Chapitre 1

Amliorer vos programmes avec les patterns

11

nouvelle version, la voiture ne peut accder son moteur quau travers des fonctions publiques et probablement bien conues de linterface de la classe Engine. Nous avons galement ouvert une possibilit dutilisation dautres types de moteurs. La classe Engine pourrait devenir une classe abstraite dont nous pourrions driver plusieurs implmentations de moteurs, toutes utilisables par notre voiture (voir Figure 1.4).Figure 1.4Dsormais, la voiture peut avoir des moteurs diffrentsCar Engine

GasolineEngine

DieselEngine

Cerise sur le gteau notre voiture nest pas condamne une seule implmentation de moteur pendant toute sa vie. Les moteurs peuvent tre remplacs au moment de lexcution :class Car def initialize @engine = GasolineEngine.new end def sunday_drive @engine.start # Aller se balader et ensuite revenir. @engine.stop end def switch_to_diesel @engine = DieselEngine.new end end

Dlguer, dlguer, dlguer Il y a une lgre diffrence fonctionnelle entre notre classe Car avec lobjet Engine spar et limplmentation initiale fonde sur lhritage. La classe initiale exposait les mthodes publiques start_engine et stop_engine. Il est videmment possible de faire de mme avec la dernire version de limplmentation en passant la responsabilit lobjet Engine :

12

Patterns et Ruby

class Car def initialize @engine = GasolineEngine.new end def sunday_drive start_engine # Aller se balader et ensuite revenir. stop_engine end def switch_to_diesel @engine = DieselEngine.new end def start_engine @engine.start end def stop_engine @engine.stop end end

Cette technique simple qui consiste "reler le bb" est connue sous le nom prtentieux de la dlgation. La mthode start_engine est appele sur lobjet Car. Lobjet dit "ce nest pas mon problme" et passe la main lobjet moteur. La combinaison de composition et de dlgation est une alternative puissante et exible lhritage. On prote de la plupart des avantages de lhritage tout en gardant beaucoup plus de exibilit et sans tre pnalis par des effets de bord. Cette facilit nest pas gratuite. La dlgation requiert un appel de mthode supplmentaire lorsquun objet passe la main un autre. Cet appel entrane un cot sur les performances, mais il reste cependant ngligeable dans la plupart des cas. La dlgation a aussi un autre cot : la ncessit dcrire du code basique savoir toutes ces mthodes ennuyeuses comme start_engine et stop_engine qui ne font que transfrer lappel lobjet nal capable de faire le traitement ncessaire. Heureusement, vous avez entre les mains un livre qui traite des design patterns en Ruby et, comme vous le verrez aux Chapitres 10 et 11, Ruby permet dviter dcrire ces mthodes ennuyeuses. Vous naurez pas besoin de a Assez parl des principes cits par le GoF en 1995. Jaimerais ajouter cette liste formidable un autre principe que je trouve critique pour dvelopper et livrer de vrais systmes. Ce principe de conception vient du monde de lExtreme Programming et est lgamment rsum en You Aint Gonna Need It (YAGNI ou "vous nen aurez pas

Chapitre 1

Amliorer vos programmes avec les patterns

13

besoin"). Le principe YAGNI stipule que vous ne devez pas implmenter des fonctionnalits ni introduire de la exibilit si vous nen avez pas un besoin immdiat. Pourquoi ? Parce quil est fort probable que vous nen ayez pas besoin plus tard non plus. Un systme bien conu est un systme qui sadapte avec lgance aux corrections de bugs, aux changements des exigences, au progrs continu de la technologie ainsi qu des remises plat invitables. Selon le principe YAGNI, il faut se concentrer sur des besoins immdiats et dvelopper prcisment le niveau de exibilit dont on est sr davoir besoin. Sans cette certitude, il vaut mieux reporter limplmentation de la fonctionnalit jusquau moment o elle devient ncessaire. Si la fonction nest pas indispensable, ne limplmentez pas, consacrez plutt votre temps et votre nergie lcriture des fonctions ncessaires dans linstant. la base du principe YAGNI on trouve un principe souvent vri qui dit que nous avons tendance nous tromper quand nous tentons danticiper nos besoins futurs. Lorsquon ajoute une nouvelle fonction ou un niveau de exibilit avant que le besoin ne se manifeste, on fait un double pari. Premirement, on parie que cette fonction sera nalement utilise. Si aujourdhui vous implmentez votre couche de persistance de manire indpendante de la base de donnes, vous faites le pari quun jour vous aurez utiliser une autre base de donnes. Si vous internationalisez linterface utilisateur, vous pariez quun jour vous aurez des utilisateurs ltranger. Comme le disait Yogi Berra (selon certaines sources), les prdictions sont difciles surtout lorsquelles concernent le futur. Sil savre que vous ne passerez jamais une autre base de donnes ou que votre application ne sera pas distribue ailleurs que dans votre pays dorigine, tout le travail effectu en amont et toute la complexit supplmentaire nauront servi rien. Le second pari que vous faites en dveloppant avant lheure est encore plus risqu. Lorsque vous implmentez une fonctionnalit ou ajoutez un niveau de exibilit trop tt, vous considrez que votre solution est bonne et que vous savez rsoudre un problme qui ne sest pas encore prsent. Vous pariez que votre couche de persistance indpendante de la base de donnes et installe avec tant damour sera adapte au systme effectivement retenu pour remplacer lancienne : "Quoi ? Le marketing veut que lon supporte xyzDB ? Je nen ai jamais entendu parler !" Vous pariez que votre solution dinternationalisation pourra supporter toute langue que vous serez amen grer : "Oh l l ! Je ne me suis pas rendu compte quil fallait supporter une langue qui scrit de droite gauche..."

14

Patterns et Ruby

Voici une faon de voir les choses : mis part la possibilit de recevoir un coup sur la tte, vous ne deviendrez pas plus bte avec le temps. Nous apprenons des choses et gagnons en intelligence chaque jour qui passe, et cest encore plus vrai dans des projets logiciel. On peut tre certain davoir une vision plus claire des contraintes, des technologies et de la conception la n dun projet qu son commencement. Lorsque vous dveloppez une fonction dont vous navez pas encore besoin, vous tes coupable de programmer btement. Attendez le moment o le besoin se manifeste et vous serez probablement en tat de mieux comprendre le besoin et la faon dy rpondre. Le but des design patterns est de rendre vos systmes plus exibles et plus adaptables aux changements. Mais, au l du temps, lusage des design patterns sest retrouv associ un courant particulirement virulent de "surengineering" visant produire du code inniment exible au risque de devenir incomprhensible et parfois mme dfectueux. Lutilisation approprie des design patterns est lart de concevoir un systme sufsamment exible pour rpondre vos besoins daujourdhui, pas plus. Un pattern est une technique utile plutt quune n en soi. Les design patterns peuvent vous aider dvelopper un systme qui fonctionne, mais le systme ne fonctionnera pas mieux si vous appliquez toutes les combinaisons imaginables des vingt-trois patterns du GoF. Votre code marchera mieux si vous restez concentr sur les tches accomplir aujourdhui.

Quatorze sur vingt-troisLes patterns prsents dans louvrage Design Patterns sont des outils pour construire des logiciels. Tout comme les outils que lon achte la quincaillerie, ils ne sont pas adapts pour toutes les situations. Certains sont comme votre marteau prfr, indispensables pour toutes vos tches ; dautres sont comme le niveau laser que lon ma offert pour mon anniversaire, parfaits lorsque vous en avez besoin, ce qui narrive que rarement. Dans ce livre, nous allons aborder quatorze des vingt-trois patterns du GoF. En faisant le choix des patterns couvrir, jai essay de me concentrer sur les pratiques les plus rpandues et les plus utiles. Par exemple, je nimagine pas coder sans utiliser des itrateurs (voir Chapitre 7), jinclus donc ce pattern sans hsiter. Je me suis galement pench vers des patterns qui se transforment lors du passage en Ruby. Une fois de plus, litrateur est un bon exemple : il mest impossible de vivre sans, mais les itrateurs en Ruby diffrent beaucoup de ceux en Java et C++. Pour vous donner un aperu de ce qui vous attend, voici une vue densemble des patterns du GoF traits dans ce livre :m

Chacun des patterns essaie de rsoudre un problme. Admettons par exemple que votre code fasse toujours la mme chose, sauf ltape 44. Parfois, ltape 44 doit

Chapitre 1

Amliorer vos programmes avec les patterns

15

sexcuter dune certaine manire et parfois dune autre. Vous aurez alors probablement besoin du pattern Template Method.m

Peut-tre est-ce la totalit de lalgorithme qui doit varier et pas seulement ltape 44. Vous avez une tche bien dnie effectuer, mais il existe plusieurs faons de le faire. Il conviendrait sans doute dencapsuler ces techniques ou algorithmes dans un objet Stratgie. Et si vous avez une classe A qui doit rester au courant des vnements intervenant dans la classe B ? Mais en vitant le couplage des deux classes car un jour viendra o la classe C (ou mme la classe D) verra le jour et exprimera le mme besoin. Il faudra alors considrer lutilisation du pattern Observateur. Parfois, il faut grer une collection en tant quun seul objet. Il doit tre possible de supprimer, dplacer ou copier un chier isol ou faire les mmes oprations sur un rpertoire entier. Si vous devez dvelopper une collection qui se comporte comme un objet individuel, vous avez probablement besoin du pattern Composite. Imaginez que vous crivez du code pour dissimuler une collection dobjets, mais que vous ne voulez pas la cacher compltement : lutilisateur doit avoir accs aux objets en squence sans savoir o ni comment ils sont stocks. Vous avez sans doute besoin du pattern Itrateur. Parfois, nos instructions doivent tre prsentes comme une sorte de carte postale : "Chre base de donnes, quand tu recevras ceci, jaimerais que tu supprimes la ligne 7843." Les cartes postales sont rares dans le code, mais le pattern Command est conu sur mesure pour ce genre de situation. Que faire lorsque vous avez un objet qui fait ce quil doit faire mais dont linterface est totalement inadquate ? Il peut sagir ici dune profonde incohrence ou plus simplement dun objet qui utilise la mthode write sur un objet qui nomme cette mthode save. Dans cette situation, le GoF recommande le pattern Adaptateur. Vous avez peut-tre le bon objet sous la main, mais il est l-bas quelque part sur le rseau et vous ne voulez pas que le client ait soccuper de son emplacement. Ou peut-tre essayerez-vous de retarder le plus possible la cration dun objet ou encore dimplmenter un contrle daccs. Dans ces circonstances, optez pour le pattern Proxy. Il est parfois ncessaire de rajouter certaines responsabilits un objet la vole, au moment de lexcution. Si vous disposez dun objet avec un certain nombre de

m

m

m

m

m

m

m

16

Patterns et Ruby

fonctionnalits mais qui de temps en temps doive prendre des responsabilits supplmentaires, il serait judicieux dutiliser le pattern Dcorateur.m

Vous pouvez avoir besoin dun objet unique dont il nexiste quune seule instance disponible pour tous les utilisateurs. Cela ressemble fort au pattern Singleton. Maintenant, imaginez que vous crivez une classe destine tre tendue. Pendant que vous tes en train de coder joyeusement la classe parent, vous vous rendez compte quelle doit instancier un nouvel objet. Seulement, la classe lle sera au courant du type dobjet crer. Vous avez probablement besoin du pattern Factory Method (Fabrication). Comment crer des familles dobjets compatibles ? Imaginez que vous ayez un systme de conception de voitures. Tous les types de moteurs ne sont pas compatibles avec toutes les sortes de carburant ou les systmes de refroidissement. Comment sassurer que lon ne nisse pas par dvelopper une voiture Frankenstein ? Cest peut-tre loccasion dutiliser une classe ddie la cration de ces objets et de lappeler Abstract Factory. Supposons que vous instanciez un objet dune telle complexit quun volume important de code soit ncessaire pour grer sa construction. Ou, pire encore, le processus de la construction est variable selon les circonstances. Vous avez probablement besoin du pattern Builder. Avez-vous dj eu le sentiment de ne pas utiliser le bon langage de programmation pour rsoudre votre problme ? Cela pourrait paratre fou, mais peut-tre que vous devriez vous arrter et dvelopper un Interprteur pour le langage spcique capable de fournir une solution simple.

m

m

m

m

Patterns en Ruby ?Voil en quelques lignes la thorie des patterns1. Mais pourquoi Ruby ? Ne sagit-il pas dun quelconque langage de script seulement appropri pour des tches dadministration systme et des interfaces graphiques Web ? En un mot : non. Ruby est un langage orient objet, lgant et universel. Il nest pas parfait pour toutes les situations par exemple, si vous avez besoin de trs haute performance, il faut, au1. videmment, je ne fais que gratter la surface dun sujet vaste et passionnant. Jetez un il sur lannexe B, Aller plus loin, pour plus dinformation.

Chapitre 1

Amliorer vos programmes avec les patterns

17

moins pour linstant, choisir un autre langage. Toutefois, Ruby est plus que convenable pour un grand nombre de tches. Ce langage a une syntaxe concise mais trs expressive et incorpore un modle de programmation riche et sophistiqu. Vous verrez dans les prochains chapitres que Ruby a sa propre faon de faire les choses, ce qui change notre approche des diffrents problmes de programmation, y compris ceux abords par des patterns classiques du GoF. Par consquent, il nest pas tonnant que la combinaison de Ruby et des design patterns classiques mne vers des dveloppements nouveaux et non traditionnels. Parfois, Ruby est sufsamment diffrent pour offrir des solutions totalement innovantes. ce propos, trois nouveaux patterns attirent lattention avec la popularit rcente de Ruby. Cest la raison pour laquelle je conclus le catalogue des patterns par les modles suivants :m

Internal DomainSpecic Language (DSL), une technique trs dynamique pour construire des petits langages spcialiss ; Mta-programmation, une technique de cration dynamique des classes et des objets au moment de lexcution ; Convention plutt que conguration, un remde contre les maux de conguration (principalement XML).

m

m

Commenons...

2Dmarrer avec RubyJai dcouvert Ruby grce mon ls de 8 ans et son amour pour une gentille souris jaune lectriquement charge1. lpoque, en 2002, mon ls passait son temps libre jouer un jeu vido dont le but tait de trouver et dapprivoiser diffrentes cratures magiques, y compris le rongeur nergtique. Un jour, jai eu limpression de voir une ampoule sallumer au-dessus de sa tte et jimaginais ses penses : "Mon papa est programmeur. Le jeu auquel je joue, le truc qui parle des les magiques et des tres merveilleux, est un programme. Mon papa fait des programmes. Mon papa peut mapprendre faire un jeu !" Eh bien, peut-tre ! Aprs une dose de harclement et de pleurnicheries que seuls les parents de jeunes enfants peuvent rellement comprendre, jai entrepris dapprendre la programmation mon ls. Tout dabord, nous avions besoin dun langage de programmation simple, clair et facilement comprhensible. Aprs une courte recherche jai trouv Ruby. Mon ls, comme le font souvent les enfants, est rapidement pass autre chose, mais Ruby avait trouv un nouvel adepte. De fait, ctait un langage propre, clair et simple parfait pour apprendre. Mais, en tant que dveloppeur professionnel qui a conu des systmes dans toutes sortes de langages allant de lassembleur Java, jai vu davantage : Ruby est concis, sophistiqu et drlement puissant. Ruby est galement trs classique. Les composants de base du langage sont des vieux engrenages connus de tous les programmeurs. Ruby possde tous les types de donnes courants : des chanes de caractres, des entiers, des nombres virgule ottante ainsi que des tableaux et nos vieux amis vrai et faux. Les bases de Ruby sont familires et ordinaires, mais la faon dont le langage est structur au plus haut niveau nous apporte une joie inattendue.1. Heureusement que la folie des Pokmon sest calme depuis.

20

Patterns et Ruby

Si vous matrisez dj les bases de Ruby, si vous avez dj crit quelques classes et savez comment extraire le troisime caractre dune chane ou comment calculer 2 puissance 437, vous pouvez passer directement au Chapitre 3. Cette section sera toujours l pour vous secourir si le besoin sen fait sentir. Ce chapitre vous est destin si vous dbutez en programmation Ruby. Le but de cette section est de vous donner le plus brivement possible un aperu des notions de base du langage. Au fond, Alan Turing avait raison lorsquil disait : "Une fois acquis un certain niveau de complexit, tous les langages de programmation deviennent quivalents." Si vous connaissez un autre langage rpandu, les bases de Ruby ne vous poseront aucun problme, vous allez "rapprendre" les choses que vous connaissez dj. Jespre qu la n de ce chapitre vous connatrez du langage juste ce quil faut pour devenir dangereux.

Ruby interactifLa faon la plus simple dexcuter du code Ruby1 consiste utiliser la console interactive irb. Aprs avoir dmarr irb, vous pouvez saisir du code Ruby et voir le rsultat instantanment. Pour lancer irb, il suft de taper irb dans le terminal. Lexemple ciaprs dmarre irb et additionne 2 et 2 laide de Ruby :$ irb irb(main):001:0> 2+2 => 4 irb(main):002:0>

La console interactive Ruby est un moyen formidable pour faire des essais petite chelle. Rien naide plus explorer un nouveau langage que la possibilit de voir le rsultat immdiatement.

Afcher Hello WorldMaintenant que Ruby est oprationnel, ltape suivante tombe sous le sens : crire votre premier programme. Voici lincontournable "Hello World" en Ruby :# # Premier programme traditionnel pour tous les langages # puts(hello world)

1. Voyez lannexe A si vous avez besoin dinstructions pour installer Ruby sur votre systme.

Chapitre 2

Dmarrer avec Ruby

21

Vous pouvez simplement dmarrer irb et entrer ce code de manire interactive. Une autre alternative est dcrire le programme avec un diteur de texte et de lenregistrer dans un chier, par exemple sous le nom hello.rb. Ensuite, vous pouvez excuter votre programme laide de linterprteur Ruby, commodment appel ruby :$ ruby hello.rb

Les deux techniques donnent un rsultat identique :hello world

Rien quen lisant le programme hello world, vous pouvez apprendre beaucoup sur un langage de programmation. Par exemple, on dcouvre que la mthode puts afche des choses. On voit galement que les commentaires commencent par le caractre # et continuent jusqu la n de la ligne. Les commentaires peuvent occuper toute la ligne, comme dans lexemple ci-dessus, ou on peut galement les placer aprs le code :puts(hello world) # Afficher bonjour

Labsence de point-virgule la n de chaque instruction est un autre point remarquable. En rgle gnrale, une instruction Ruby se termine par un saut de ligne. Les programmeurs Ruby ont tendance utiliser des points-virgules uniquement pour sparer des instructions multiples sur la mme ligne, et ce dans les rares cas o ils dcident dentasser plusieurs instructions sur une ligne :# # Usage valide, mais atypique dun point-virgule en Ruby # puts(hello world); # # Un peu plus de rigueur. Utilisation toujours rare dun point-virgule # puts(hello ); puts(world)

Lanalyseur syntaxique de Ruby est sufsamment intelligent pour poursuivre son analyse sur la ligne suivante lorsquune instruction est clairement inacheve. Par exemple, le code ci-aprs fonctionne bien, car lanalyseur syntaxique dduit de loprateur + la n de la ligne que linstruction continue sur une deuxime ligne :x = 10 + 20 + 30

Une instruction peut indiquer explicitement avec une barre oblique inverse quelle stend sur la ligne suivante :x = 10 \ + 10

22

Patterns et Ruby

On voit ici merger un principe rcurrent de la philosophie Ruby qui consiste aider lutilisateur lorsquil a besoin dassistance et seffacer en toute autre circonstance. Selon cette philosophie, Ruby permet domettre les parenthses si elles naident pas clarier une liste darguments :puts hello world

Pour des raisons de clart, la plupart des exemples de ce livre incluent les parenthses dans les appels de mthodes sauf si aucun argument nest fourni, et dans ce cas les parenthses vides sont omises. Dans le programme "hello world" nous avons entour la chane de caractres de guillemets simples, mais les guillemets doubles peuvent tout aussi bien tre utiliss :puts("hello world")

Le rsultat obtenu avec des guillemets simples ou doubles est le mme, mais avec une petite subtilit. Les guillemets simples ont pour effet dafcher littralement ce que vous voyez car Ruby ne fait que trs peu dinterprtations sur de telles chanes de caractres. Ce nest pas le cas des guillemets doubles, qui provoquent un traitement classique en amont : \n est converti en un caractre de saut de ligne, \t devient une tabulation. Si la chane abc\n compte cinq caractres (les deux derniers sont la barre oblique inverse et la lettre "n"), la longueur de la chane "abc\n" nest que de quatre caractres (le dernier caractre tant le saut de ligne). Finalement, vous avez probablement remarqu que la chane hello world que nous avons passe loprateur puts ninclut pas de \n. Pourtant, cet oprateur a ajout un saut de ligne la n du message. En ralit, loprateur puts est assez intelligent. Il rajoute un saut de ligne au texte de sortie sil en manque un. Ce comportement nest pas forcment souhait pour le formatage de prcision, mais il est parfaitement adapt pour les exemples que vous trouverez dans ce livre.

VariablesLes noms des variables ordinaires en Ruby commencent par une lettre minuscule ou un tiret bas (nous verrons quelques variables inhabituelles plus tard) 1. Le premier caractre peut tre suivi par des lettres minuscules ou majuscules, des tirets bas ainsi que des chiffres. Les noms des variables sont sensibles la casse et la seule limite la longueur1. Dans la plupart des cas, Ruby considre le tiret bas comme un caractre minuscule.

Chapitre 2

Dmarrer avec Ruby

23

des variables Ruby est votre imagination. Tous les noms ci-aprs reprsentent des noms de variables valides :m m m m m m m m

max_length maxLength numberPages numberpages a_very_long_variable_name _flag column77Row88 ___

Les deux noms max_length et maxLength voquent un point important : les noms en casse mixte sont parfaitement accepts en Ruby et, pourtant, les dveloppeurs Ruby ont tendance ne pas les utiliser. La pratique la plus rpandue parmi les programmeurs Ruby bien levs est de sparer_des_mots_par_des_tirets_bas. Puisque les noms des variables sont sensibles la casse, numberPages et numberpages sont deux variables diffrentes. Enn, le dernier nom dans la liste comprend seulement trois tirets bas. Cest certes une pratique valide mais viter1. Assemblons maintenant nos chanes de caractres et nos variables :first_name = russ last_name = olsen full_name = first_name + + last_name

Cet exemple illustre trois affectations basiques : la chane de caractres russ est attribue la variable first_name, la valeur olsen est attribue last_name et full_name reoit la concatnation de mon prnom et de mon nom spars par une espace. Vous avez peut-tre remarqu quaucune des variables nest dclare dans cet exemple. Rien ne dclare que la variable first_name est et restera toujours une chane de caractres. Ruby est un langage dynamiquement typ, ce qui signie que les variables ne possdent pas de type xe. En Ruby vous pouvez faire apparatre un nom de variable comme par magie et lui